How to programmatically draw an organization chart? - graphics

Users of my program are organized hierarchically. Each user is a node in a tree, and the only other type of node is the department node. Each node has one and only one parent (possibly the root node).
I generated a DOT file to be used by the graphviz suite, but the resulting picture is unusable because it's too wide. I don't know if this program can be tuned to suit my needs, because I have a flat hierarchy with lots of sibling nodes, so maybe I need a program specifically designed for this (or write my own). I tried the unflatten tool, but without success.
This is the test dot file - note that my program often uses 10x this data...

Based on your comment, here's a quick test using other layout algorithms than dot. Since you said circle, I tried with circo and twopi.
I had to make some slight changes to the test script:
add some colors/shape/style/font
style user and department nodes differently
insert a newline between the name and the function of the users
Putting the long department names on two lines would probably help, too.
digraph G {
overlap=false;
splines=true;
root="node0";
node[colorscheme=paired12, fontsize=11];
node0 [shape=house, label="Organizzazione", style="filled", fillcolor=3, color="4", fontsize=20, height=2,
fontname="Times New Roman Bold"];
node[shape=doubleoctagon, style=filled, fillcolor=7, color=8, width=3];
node24 [label="C3 TERREMOTO"];
node28 [label="E POLIZIA URBANA E PROTEZIONE CIVILE"];
node14 [label="D1 SERVIZI SCOLASTICI"];
node35 [label="30: PROTOCOLLO ADMIN "];
node18 [label="B ECONOMICO E FINANZIARIO"];
node22 [label="C ASSETTO E TERRITORIO"];
node41 [label="A9 UFFICIO PUBBLICAZIONI"];
node38 [label="C1 TECNICO"];
node31 [label="A AFFARI GENERALI"];
node12 [label="A4 ANAGRAFE E STATO CIVILE"];
node20 [label="B1 TRIBUTI"];
node16 [label="A5 ELETTORALE E LEVA"];
node40 [label="31: PUBBLICAZIONI ALBO UTENTE "];
node26 [label="C2a TECNICO"];
node9 [label="A3 UFFICIO PROTOCOLLO CENTRALE"];
node[shape=box, style=filled, fillcolor="1", color="2", width=2];
node0 -> node24;
node0 -> node28;
node7 [label="14: ROCCO MARINACCIO\nVISUALIZZATORE"];
node0 -> node7;
node25 [label="27: FRANCESCO MARINO "];
node26 -> node25;
node39 [label="5: CIRO D'EMILIO\nPROTOCOLLATORE"];
node20 -> node39;
node4 [label="15: FRANCESCO PAZIENZA\nVISUALIZZATORE"];
node0 -> node4;
node3 [label="18: ADRIANA NATALE\nVISUALIZZATRICE"];
node0 -> node3;
node42 [label="4: MICHELE ROGATO\nRESP DI REPARTO"];
node18 -> node42;
node29 [label="29: FRANCESCO NOTA "];
node28 -> node29;
node0 -> node14;
node10 [label="12: STEFANO IEFFA "];
node0 -> node10;
node13 [label="20: ANTONIO MARINO "];
node14 -> node13;
node30 [label="3: PATRIZIA PLATANO\nPROTOCOLLATRICE"];
node31 -> node30;
node1 [label="19: PATRIZIA PLATANO "];
node0 -> node1;
node37 [label="6: GIUSEPPE CEGLIA\nRESP. DI REPARTO"];
node38 -> node37;
node0 -> node35;
node0 -> node18;
node23 [label="26: PASQUALE RUSSO "];
node24 -> node23;
node2 [label="17: MICHELE BICCARINO\nVISUALIZZATORE"];
node0 -> node2;
node0 -> node22;
node0 -> node41;
node11 [label="21: GIUSEPPE DI FLUMERI "];
node12 -> node11;
node43 [label="9: ROBERTO CAMPANELLA "];
node0 -> node43;
node0 -> node38;
node0 -> node31;
node0 -> node12;
node0 -> node20;
node17 [label="23: MICHELE IPPOLITO "];
node18 -> node17;
node6 [label="13: ALESSANDRO CAPANO "];
node0 -> node6;
node19 [label="24: SALVATORE DOTO "];
node20 -> node19;
node15 [label="22: BENVENUTA REA "];
node16 -> node15;
node27 [label="28: ANTONIO CAMPANELLA "];
node28 -> node27;
node8 [label="11: PASQUALE PALUMBO "];
node9 -> node8;
node5 [label="16: PAOLO PIETRO TROCCOLA\nVISUALIZZATORE"];
node0 -> node5;
node0 -> node16;
node21 [label="25: RAFFAELA COFANO "];
node22 -> node21;
node41 -> node40;
node32 [label="2: MARIA CRISTINA ANELLI\nVISUALIZZATRICE"];
node0 -> node32;
node0 -> node26;
node33 [label="10: VINCENZO BOTTICELLI "];
node0 -> node33;
node0 -> node9;
node36 [label="7: ANTONIETTA STRAZZELLA\nRESP. DI REPARTO"];
node22 -> node36;
node34 [label="1: AMBROGIO MASCIA\nAmministratore di sistema"];
node9 -> node34;
node44 [label="8: MARIANO LAUDISI\nVISUALIZZATORE"];
node0 -> node44;
}
You'll probably have to open the images and look at them in the original size.
Twopi layout:
Circo layout:
The circo layout could probably be more appropriate if you have department linked to departments, or a lot of users in one department.

The dot language has a lot of subtle ways to modify the image to make it more pleasing. Take a few minutes out and skim the dot guide. You can set constraints on pretty much any aspect from the X/Y ratio of the page, the repulsion and layout of nodes.
One of the contrib packages available with graphviz is GVEdit, which is a little Qt app that links to the graphviz libraries - one window to edit graphs, hit 'go' and it'll render to another window. Great instant feedback method of making things pretty.

Related

MailboxProcessor Scan memory leak

Consider the following agent which uses Scan to process every message, with a message posted every millisecond.
open System.Threading
let mp = MailboxProcessor<string>.Start (fun inbox ->
let rec await () = inbox.Scan (fun msg ->
printfn "Received : %s" msg
printfn "Queue length: %i" inbox.CurrentQueueLength
Some <| await ())
await ())
while true do
mp.Post "word"
Thread.Sleep 1
If I monitor the memory usage of the process (macOS, via Activity Monitor), it grows and grows. Yet you can see from the printout that the queue length remains at 0.
Is this a memory leak bug in Scan or am I doing something wrong?

Memory Leak in Ninject

I'm investigating a webapp which ran up to 10gb of memory, by analysing a memory dump using Windbg.
Here's the bottom of the !dumpheap -stat output:
00007ff9545df5d0 166523 13321840 System.Runtime.Caching.MemoryCache
00007ff9545df4a0 166523 14654024 System.Runtime.Caching.CacheMemoryMonitor
00007ff9545de990 166523 14654024 System.Runtime.Caching.SRef[]
00007ff9545dcef0 166523 14654024 System.Runtime.Caching.GCHandleRef`1[[System.Runtime.Caching.MemoryCacheStore, System.Runtime.Caching]][]
00007ff9545dfb28 166523 19982760 System.Runtime.Caching.MemoryCacheStatistics
00007ff956778510 333059 21315680 System.Int64[]
00007ff95679c988 41597 31250111 System.Byte[]
00007ff9545e08c8 1332184 31972416 System.Runtime.Caching.MemoryCacheEqualityComparer
00007ff9545dfe48 1332184 31972416 System.Runtime.Caching.SRef
00007ff956780ff0 1332200 31972800 System.SizedReference
00007ff956724620 1498777 35970648 System.Threading.TimerHolder
00007ff95677fb30 1536170 36868080 System.Runtime.Remoting.Messaging.CallContextSecurityData
00007ff956796f28 1606960 38567040 System.Object
00007ff9545df810 1332184 42629888 System.Runtime.Caching.GCHandleRef`1[[System.Runtime.Caching.MemoryCacheStore, System.Runtime.Caching]]
00007ff9545dda38 1332184 42629888 System.Runtime.Caching.UsageBucket[]
00007ff9567ae930 1332268 42632576 Microsoft.Win32.SafeHandles.SafeWaitHandle
00007ff9545df968 1498707 47958624 System.Runtime.Caching.GCHandleRef`1[[System.Threading.Timer, mscorlib]]
00007ff9567adbf8 1498777 47960864 System.Threading.Timer
00007ff9545dff50 1332184 53287360 System.Runtime.Caching.CacheUsage
00007ff94986ead8 1536137 61445480 System.Web.Hosting.AspNetHostExecutionContextManager+AspNetHostExecutionContext
00007ff9567a2838 1332210 63946080 System.Threading.ManualResetEvent
00007ff956796948 293525 66384986 System.String
00007ff9545dfef0 1332184 74602304 System.Runtime.Caching.CacheExpires
00007ff9567add20 1498760 95920640 System.Threading.TimerCallback
00007ff9545dfa90 1332184 106574720 System.Runtime.Caching.MemoryCacheStore
00007ff95679b3b0 1333289 106663120 System.Collections.Hashtable
00007ff95678f138 1536171 110604312 System.Runtime.Remoting.Messaging.LogicalCallContext
00007ff9545dffb0 1332184 127889664 System.Runtime.Caching.UsageBucket
00007ff95679d1e0 1333292 128664768 System.Collections.Hashtable+bucket[]
00007ff9567245c0 1498777 131892376 System.Threading.TimerQueueTimer
00007ff9567aec48 1536255 135190440 System.Threading.ExecutionContext
00007ff9545dcf78 1332184 351696576 System.Runtime.Caching.ExpiresBucket[]
000000f82c79d9f0 473339 385303992 Free
00007ff956799220 40309535 1617342672 System.Int32[]
00007ff9545e0468 39965520 3836689920 System.Runtime.Caching.ExpiresBucket
So there are nearly 40 million instances of System.Runtime.Caching.ExpiresBucket, totally nearly 4gb of the used memory. System.Runtime.Caching classes appear quite a lot in the top offenders.
I took a random instance of a System.Runtime.Caching.ExpiresBucket class, and did a !gcroot on it. It took ages (maybe 30 mins) to produce 1 thread...there may have been more but I interrupted the operation at this point.
The chain of references is over 1.5 million lines long! But I can show the important bits here:
0:000> !gcroot 000000f82dd4bc28
Thread 1964:
000000fcbdbce6a0 00007ff8f9bbe388 Microsoft.AspNet.SignalR.SqlServer.ObservableDbOperation.ExecuteReaderWithUpdates(System.Action`2<System.Data.IDataRecord,Microsoft.AspNet.SignalR.SqlServer.DbOperation>)
rbp-58: 000000fcbdbce6e8
-> 000000fa2d1f26a0 Microsoft.AspNet.SignalR.SqlServer.ObservableDbOperation+<>c__DisplayClass1e
-> 000000fa2d1f2110 Microsoft.AspNet.SignalR.SqlServer.ObservableDbOperation
-> 000000fa2d1f24d0 System.Action
-> 000000fa2d1f24a8 System.Object[]
-> 000000fa2d1f2468 System.Action
-> 000000fa2d1f1008 Microsoft.AspNet.SignalR.SqlServer.SqlReceiver
-> 000000fa2d1f1330 System.Action
-> 000000fa2d1f1308 System.Object[]
-> 000000fa2d1f12c8 System.Action
-> 000000fa2d1efb70 Microsoft.AspNet.SignalR.SqlServer.SqlStream
-> 000000fa2d1f1528 System.Action
-> 000000fa2d1f1500 System.Object[]
-> 000000fa2d1f14c0 System.Action
-> 000000fa2d1efb20 Microsoft.AspNet.SignalR.SqlServer.SqlMessageBus+<>c__DisplayClass3
-> 000000f92d0b84e0 Microsoft.AspNet.SignalR.SqlServer.SqlMessageBus
-> 000000f92d0b9568 System.Threading.Timer
-> 000000f92d0b96d8 System.Threading.TimerHolder
-> 000000f92d0b95a0 System.Threading.TimerQueueTimer
[... about 100 lines of the same TimerQueueTimer line above, but different memory addresses each time]
-> 000000f92cf1be68 System.Threading.TimerQueueTimer
-> 000000f92cf1be08 System.Threading.TimerCallback
-> 000000f92cf1bb48 System.Web.RequestTimeoutManager
-> 000000f92cf1bb80 System.Web.Util.DoubleLinkList[]
-> 000000f92cf1bc00 System.Web.Util.DoubleLinkList
-> 000000fb61323860 System.Web.RequestTimeoutManager+RequestTimeoutEntry
-> 000000fb6131fd38 System.Web.HttpContext
-> 000000fbe682a480 ASP.global_asax
-> 000000fbe682ac00 System.Web.HttpModuleCollection
-> 000000fbe682ac60 System.Collections.ArrayList
-> 000000fbe682b598 System.Object[]
-> 000000fbe682b018 System.Collections.Specialized.NameObjectCollectionBase+NameObjectEntry
-> 000000fbe682b000 System.Web.Routing.UrlRoutingModule
-> 000000faacec1f40 System.Web.Routing.RouteCollection
-> 000000faacec2030 System.Collections.Generic.List`1[[System.Web.Routing.RouteBase, System.Web]]
-> 000000fa2cfe4d80 System.Web.Routing.RouteBase[]
-> 000000f9acf14cd8 System.Web.Http.WebHost.Routing.HttpWebRoute
-> 000000f9acf149f8 System.Web.Http.Routing.RouteCollectionRoute
-> 000000f9acf1f4f0 System.Web.Http.Routing.SubRouteCollection
-> 000000f9acf1f510 System.Collections.Generic.List`1[[System.Web.Http.Routing.IHttpRoute, System.Web.Http]]
-> 000000fa2cf8f310 System.Web.Http.Routing.IHttpRoute[]
-> 000000fa2ceff770 System.Web.Http.Routing.HttpRoute
-> 000000fa2ceff678 System.Web.Http.Routing.HttpRouteValueDictionary
-> 000000fa2ceff6f0 System.Collections.Generic.Dictionary`2+Entry[[System.String, mscorlib],[System.Object, mscorlib]][]
-> 000000fa2cef9e78 System.Web.Http.Controllers.HttpActionDescriptor[]
-> 000000fa2cef7898 System.Web.Http.Controllers.ReflectedHttpActionDescriptor
-> 000000f9aced4608 System.Web.Http.HttpConfiguration
-> 000000f9aced4db0 System.Net.Http.Formatting.MediaTypeFormatterCollection
-> 000000f9aced6f40 System.Collections.Generic.List`1[[System.Net.Http.Formatting.MediaTypeFormatter, System.Net.Http.Formatting]]
-> 000000f9aced6f80 System.Net.Http.Formatting.MediaTypeFormatter[]
-> 000000f9aced4df8 System.Net.Http.Formatting.JsonMediaTypeFormatter
-> 000000f9acf1f448 System.Web.Http.Validation.ModelValidationRequiredMemberSelector
-> 000000f9acf1f468 System.Collections.Generic.List`1[[System.Web.Http.Validation.ModelValidatorProvider, System.Web.Http]]
-> 000000f9acf1f490 System.Web.Http.Validation.ModelValidatorProvider[]
-> 000000f9acf1db40 Ninject.Web.WebApi.Validation.NinjectDefaultModelValidatorProvider
-> 000000faaceca438 Ninject.StandardKernel
-> 000000faaceca498 Ninject.Components.ComponentContainer
-> 000000faaceca538 System.Collections.Generic.Dictionary`2[[System.Type, mscorlib],[Ninject.Components.INinjectComponent, Ninject]]
-> 000000f9acece000 System.Collections.Generic.Dictionary`2+Entry[[System.Type, mscorlib],[Ninject.Components.INinjectComponent, Ninject]][]
-> 000000f9acecdac8 Ninject.Activation.Caching.GarbageCollectionCachePruner
-> 000000f9acecdcb8 System.Threading.Timer
-> 000000f9acecdd30 System.Threading.TimerHolder
-> 000000f9acecdcd8 System.Threading.TimerQueueTimer
[... just under 1.5 million lines of the same TimerQueueTimer line above, but different memory addresses each time]
-> 000000f82dd4c028 System.Threading.TimerQueueTimer
-> 000000f82dd4bfc8 System.Threading.TimerCallback
-> 000000f82dd4ada0 System.Runtime.Caching.CacheExpires
-> 000000f82dd4add8 System.Runtime.Caching.ExpiresBucket[]
-> 000000f82dd4bc28 System.Runtime.Caching.ExpiresBucket
Running !objsize on the 000000faaceca438 Ninject.StandardKernel seems to take forever, implying that it references an awful lot of objects, possibly all 40 million of those System.Runtime.Caching.ExpiresBucket objects...
What is causing the leak? How should I go about identifying the offending class or code? There is no reference to any of our own code in the gcroot output, so is it due to a bug in one of the installed libraries we're using? Is it in Ninject? We're using v3.2.2 (not the latest, I know)
Posting as an answer because it's too long for a comment:
Seems to me Ninject is tracking an awful lot of scope-objects. AFAIR that's what the GarbageCollectionPruner is for. A scope object is something that is defined with .InScope(...this object here...) or with some of the overloads like InRequestScope().
GarbageCollectionPruner has a timer that periodically checks whether the scope is still "alive". And if it is not alive anymore (garbage collected) it will dispose & forget all objects associated with that scope.
Unless there's not a bug in ninject, this would mean your application is creating an awful lot of scopes in a short interval or they are not properly cleaned up (meaning: problem with your or other 3rd party code).
By the way, if the scope object implements INotifyWhenDisposed (ninject interface) the periodical IsAlive check is not necessary and also gives the benefit of "determnistic" disposal, i.E. just when the scope ends the scoped objects are disposed, too. Otherwise this is dependent on the GC and the timer in Ninject...

Linux Framebuffer modes

I am currently working on embedded linux framebuffers. I know how to display the available resolutions of my system by typing:
cat /sys/class/graphics/fb0/modes
This gives me a list of resolutions, for instance:
U:720x576p-50
D:1920x1080p-50
D:1280x720p-50
D:1920x1080i-60
D:1920x1080i-50
U:1440x900p-60
S:1280x1024p-60
V:1024x768p-60
V:800x600p-60
V:640x480p-60
D:1280x720p-60
D:1920x1080p-60
I would like to know what does the first character of each lines mean (S, U, V or D).
Is there a standard/documentation listing all the possible characters?
From the linux kernel source function mode_string()
char m = 'U';
if (mode->flag & FB_MODE_IS_DETAILED)
m = 'D';
if (mode->flag & FB_MODE_IS_VESA)
m = 'V';
if (mode->flag & FB_MODE_IS_STANDARD)
m = 'S';
so it's U unknown, D detailed, V vesa, S standard.

Disseminating a token in Alloy

I'm following an example in Daniel Jackson's excellent book (Software Abstractions), specifically the example in which he has a token-ring setup in order to elect a leader.
I'm attempting to extend this example (Ring election) to ensure that the token, instead of being limited to one, is being passed around to all members within the provided time (and each member only being elected once, not multiple times). However (mostly due to my inexperience in Alloy), I'm having issues figuring out the best way. Initially I'd thought that I could play with some of the operators (changing -'s to +'s), but I don't seem to be quite hitting the nail on the head.
Below is the code from the example. I've marked up a few areas with questions...any and all help is appreciated. I'm using Alloy 4.2.
module chapter6/ringElection1 --- the version up to the top of page 181
open util/ordering[Time] as TO
open util/ordering[Process] as PO
sig Time {}
sig Process {
succ: Process,
toSend: Process -> Time,
elected: set Time
}
// ensure processes are in a ring
fact ring {
all p: Process | Process in p.^succ
}
pred init [t: Time] {
all p: Process | p.toSend.t = p
}
//QUESTION: I'd thought that within this predicate and the following fact, that I could
// change the logic from only having one election at a time to all being elected eventually.
// However, I can't seem to get the logic down for this portion.
pred step [t, t': Time, p: Process] {
let from = p.toSend, to = p.succ.toSend |
some id: from.t {
from.t' = from.t - id
to.t' = to.t + (id - p.succ.prevs)
}
}
fact defineElected {
no elected.first
all t: Time-first | elected.t = {p: Process | p in p.toSend.t - p.toSend.(t.prev)}
}
fact traces {
init [first]
all t: Time-last |
let t' = t.next |
all p: Process |
step [t, t', p] or step [t, t', succ.p] or skip [t, t', p]
}
pred skip [t, t': Time, p: Process] {
p.toSend.t = p.toSend.t'
}
pred show { some elected }
run show for 3 Process, 4 Time
// This generates an instance similar to Fig 6.4
//QUESTION: here I'm attempting to assert that ALL Processes have an election,
// however the 'all' keyword has been deprecated. Is there an appropriate command in
// Alloy 4.2 to take the place of this?
assert OnlyOneElected { all elected.Time }
check OnlyOneElected for 10 Process, 20 Time
This network protocol is exactly about how to elect a single process to be the leader, so I don't really understand the meaning of your idea of having "all processes elected eventually".
instead of all elected.Time, you can equivalently write elected.Time = Process (since the type of elected is Process -> Time). This just says that elected.Time (all processes elected at any time step) is exactly the set of all processes, which, obviously, doesn't mean that "only one process is elected", as suggested by the name of your assertion.

prio, static_prio, rt_priority in Linux Kernel

What is the difference between each value of task_struct?
Here's my notes on the priority fields. I also include how data is presented via the 'ps' command (which gets it's data from /proc/pid/stat, among other things).
task_struct.prio:
0-99 -> Realtime
100-140 -> Normal priority
ps/stat "prio" field:
task_struct.prio - MAX_RT_PRIO (100)
(-100)-(-1) -> Realtime
0-40 -> Normal Priority
stat "rt_priority" field:
0 -> normal
1-99 -> realtime
stat "policy" field:
0 -> SCHED_OTHER (normal)
1 -> SCHED_FIFO
2 -> SCHED_RR (realtime)

Resources