benchmark silo added
[c11concurrency-benchmarks.git] / silo / masstree / doc / elements.mp
1 % elements.mp -- MetaPost macros for drawing Click configuration graphs
2 % Eddie Kohler
3 %
4 % Copyright (c) 1999-2001 Massachusetts Institute of Technology
5 % Copyright (c) 2001-2003 International Computer Science Institute
6 % Copyright (c) 2006 Regents of the University of California
7 %
8 % Permission is hereby granted, free of charge, to any person obtaining a
9 % copy of this software and associated documentation files (the "Software"),
10 % to deal in the Software without restriction, subject to the conditions
11 % listed in the Click LICENSE file. These conditions include: you must
12 % preserve this copyright notice, and you cannot mention the copyright
13 % holders in advertising related to the Software without their permission.
14 % The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
15 % notice is a summary of the Click LICENSE file; the license in that file is
16 % legally binding.
17
18 input rboxes;
19 prologues := 1;
20 string defaultelementfont;
21 defaultscale := 1;
22 linejoin := mitered;
23
24 pair element_offset;
25 element_offset = (7.5, 4.5);
26 min_element_height = 19;
27 element_height_increment = 4;
28
29 defaultelementborderscale = 1;
30 defaultelementportscale = 1;
31
32 port_length = 6;
33 port_sep = 3;
34 port_offset = 4;
35 input_length = 7;
36 input_width = 4.5;
37 output_length = 6;
38 output_width = 3.8;
39 agnostic_sep = 1;
40
41 push = 0;
42 pull = 1;
43 agnostic = 2;
44 agnostic_push = 3;
45 agnostic_pull = 4;
46 push_to_pull = 5;
47 pull_to_push = 6;
48
49 pen elementpen.border, elementpen.port, connectionpen;
50 elementpen.border = pencircle scaled 0.9;
51 elementpen.port = pencircle scaled 0.35;
52 connectionpen = pencircle scaled 0.45;
53
54 color personalitycolor[], agnosticcolor[];
55 personalitycolor[push] = black;
56 personalitycolor[agnostic_push] = personalitycolor[agnostic] = white;
57 personalitycolor[pull] = personalitycolor[agnostic_pull] = white;
58 agnosticcolor[agnostic_push] = black;
59 agnosticcolor[agnostic_pull] = white;
60 agnosticcolor[agnostic] = 0.6white;
61
62 path _agnostic_output, _agnostic_input, _normal_output, _normal_input;
63 _agnostic_output := ((-.5,0.5output_length-agnostic_sep)
64   -- (-output_width+agnostic_sep,0.5output_length-agnostic_sep)
65   -- (-output_width+agnostic_sep,-0.5output_length+agnostic_sep)
66   -- (-.5,-0.5output_length+agnostic_sep) -- cycle);
67 _agnostic_input := ((.5,0.5input_length-1.414agnostic_sep)
68   -- (input_width-1.414agnostic_sep,0)
69   -- (.5,-0.5input_length+1.414agnostic_sep) -- cycle);
70 _normal_input := ((.5,0.5input_length) -- (input_width,0)
71     -- (.5,-0.5input_length) -- cycle);
72 _normal_output := ((-.5,0.5output_length) -- (-output_width,0.5output_length)
73     -- (-output_width,-0.5output_length) -- (-.5,-0.5output_length) -- cycle);
74
75
76 %% redefine 'drawboxes' to allow extra text
77
78 vardef drawboxes(text t) text rest =         % Draw boundary path for each box
79   forsuffixes s=t: draw bpath.s rest; endfor
80 enddef;
81
82
83 %%
84
85 vardef _make_element_ports(suffix $, port, side)(expr n, length, isout) =
86   save _i_, _sc; pair _sc.adj;
87   _sc.sep = (length - 2*port_offset - n*port_length + port_sep) / n;
88   _sc.delta = port_length + _sc.sep;
89   _sc = length/2 - port_offset - (_sc.sep - port_sep)/2 - 0.5port_length;
90   _sc.adj = if isout: 1/2$.flowvector else: -1/2$.flowvector fi;
91   for _i_ = 0 upto n-1:
92     $.port[_i_] = $.side + $.sidevector * (_sc - _sc.delta*_i_) + _sc.adj;
93   endfor;
94 enddef;
95
96 vardef make_element_inputs(suffix $)(expr xlen, ylen) =
97   if $.down:
98     _make_element_ports($, in, if $.rev: s else: n fi, $.nin, xlen-6, false);
99   else:
100     _make_element_ports($, in, if $.rev: e else: w fi, $.nin, ylen, false);
101   fi;
102 enddef;
103
104 vardef make_element_outputs(suffix $)(expr xlen, ylen) =
105   if $.down:
106     _make_element_ports($, out, if $.rev: n else: s fi, $.nout, xlen-6, true);
107   else:
108     _make_element_ports($, out, if $.rev: w else: e fi, $.nout, ylen, true);
109   fi;
110 enddef;
111
112 vardef clearelement_(suffix $) =
113   _n_ := str $;
114   generic_redeclare(numeric) _n.down, _n.rev, _n.sidevector, _n.flowvector, _n.width, _n.height, _n.nin, _n.nout, _n.borderscale, _n.portscale, _n.drawports;
115   _n_ := str $ & ".in0";
116   generic_redeclare(numeric) _n;
117   _n_ := str $ & ".out0";
118   generic_redeclare(numeric) _n;
119   _n_ := str $ & ".inpers0";
120   generic_redeclare(numeric) _n;
121   _n_ := str $ & ".outpers0";
122   generic_redeclare(numeric) _n;
123   _n_ := "elemdraw_." & str $;
124   generic_redeclare(numeric) _n;
125 enddef;
126
127 vardef _elementit@#(expr label_str, ninputs, noutputs, personality, down_var, rev_var) =
128   picture _label_; numeric _x_, _y_;
129   
130   if picture label_str: _label_ = label_str
131   elseif label_str = "": _label_ = nullpicture
132   else: _label_ = label_str infont defaultelementfont scaled defaultscale
133   fi;
134   
135   boxit.@#(_label_);
136   _n_ := str @#;
137   generic_declare(boolean) _n.down, _n.rev, _n.drawports;
138   generic_declare(pair) _n.sidevector, _n.flowvector;
139   generic_declare(numeric) _n.width, _n.height, _n.nin, _n.nout, _n.borderscale, _n.portscale;
140   _n_ := str @# & ".in0";
141   generic_declare(pair) _n;
142   _n_ := str @# & ".out0";
143   generic_declare(pair) _n;
144   _n_ := "elemdraw_." & str @#;
145   generic_declare(string) _n;
146   
147   @#.down = down_var;
148   if down_var: @#.sidevector = (-1, 0); else: @#.sidevector = (0, 1); fi;
149   if down_var: @#.flowvector = (0, -1); else: @#.flowvector = (1, 0); fi;
150   @#.rev = rev_var;
151   if rev_var: @#.flowvector := -@#.flowvector; @#.sidevector := -@#.sidevector; fi;
152   @#.drawports = true;
153   
154   @#.width = xpart(@#.e - @#.w);
155   @#.height = ypart(@#.n - @#.s);
156   
157   @#.nin = ninputs;
158   @#.nout = noutputs;
159   if ninputs > 0: make_element_inputs(@#, @#.width, @#.height); fi;
160   if noutputs > 0: make_element_outputs(@#, @#.width, @#.height); fi;
161   
162   _x_ := personality;
163   if _x_ = push_to_pull: _x_ := push;
164   elseif _x_ = pull_to_push: _x_ := pull; fi;
165   for _y_ = 0 upto ninputs-1: @#.inpers[_y_] = _x_; endfor;
166   
167   _x_ := personality;
168   if _x_ = push_to_pull: _x_ := pull;
169   elseif _x_ = pull_to_push: _x_ := push; fi;
170   for _y_ = 0 upto noutputs-1: @#.outpers[_y_] = _x_; endfor;
171   
172   elemdraw_@# = "drawboxes";
173   sproc_@# := "sizeelement_";
174   
175   expandafter def expandafter clearboxes expandafter =
176     clearboxes clearelement_(@#);
177   enddef
178 enddef;
179
180 vardef elementit@#(expr s, ninputs, noutputs, personality_var) =
181   _elementit.@#(s, ninputs, noutputs, personality_var, false, false);
182 enddef;
183 vardef relementit@#(expr s, ninputs, noutputs, personality_var) =
184   _elementit.@#(s, ninputs, noutputs, personality_var, false, true);
185 enddef;
186 vardef velementit@#(expr s, ninputs, noutputs, personality_var) =
187   _elementit.@#(s, ninputs, noutputs, personality_var, true, false);
188 enddef;
189 vardef rvelementit@#(expr s, ninputs, noutputs, personality_var) =
190   _elementit.@#(s, ninputs, noutputs, personality_var, true, true);
191 enddef;
192
193
194 %% change
195
196 vardef killinput(suffix $)(expr p) =
197   if (p >= 0) and (p < $.nin): save _i_;
198     for _i_ = p upto $.nin-2:
199       $.in[_i_] := $.in[_i_+1];
200       $.inpers[_i_] := $.inpers[_i_+1];
201     endfor;
202     $.nin := $.nin - 1
203   fi
204 enddef;
205
206 vardef killoutput(suffix $)(expr p) =
207   if (p >= 0) and (p < $.nout): save _i_;
208     for _i_ = p upto $.nout-2:
209       $.out[_i_] := $.out[_i_+1];
210       $.outpers[_i_] := $.outpers[_i_+1];
211     endfor;
212     $.nout := $.nout - 1
213   fi
214 enddef;
215
216 vardef portinteriorin(suffix $)(expr i) =
217   path _p_;
218   _p_ := if $.inpers[i] >= agnostic: _agnostic_input else: _normal_input fi
219     scaled $.portscale;
220   if $.down: _p_ := _p_ rotated -90 fi;
221   if $.rev: _p_ := _p_ rotated 180 fi;
222   _p_ := _p_ shifted $.in[i];
223   if $.down and $.rev: .5[ulcorner _p_,urcorner _p_]
224   elseif $.down: .5[llcorner _p_,lrcorner _p_]
225   elseif $.rev: .5[ulcorner _p_,llcorner _p_]
226   else: .5[urcorner _p_,lrcorner _p_] fi
227 enddef;
228
229 vardef portinteriorout(suffix $)(expr i) =
230   path _p_;
231   _p_ := if $.outpers[i] >= agnostic: _agnostic_output else: _normal_output fi
232     scaled $.portscale;
233   if $.down: _p_ := _p_ rotated -90 fi;
234   if $.rev: _p_ := _p_ rotated 180 fi;
235   _p_ := _p_ shifted $.out[i];
236   if $.down and $.rev: .5[llcorner _p_,lrcorner _p_]
237   elseif $.down: .5[ulcorner _p_,urcorner _p_]
238   elseif $.rev: .5[urcorner _p_,lrcorner _p_]
239   else: .5[ulcorner _p_,llcorner _p_] fi
240 enddef;
241
242
243 %% fix
244
245 vardef set_element_dx(suffix $) =
246   if $.down: save x;
247     x.maxport = max($.nin, $.nout);
248     x.len = x.maxport*port_length + (x.maxport-1)*port_sep + 2port_offset;
249     x.w = xpart(urcorner pic_$ - llcorner pic_$);
250     x.ww = x.w + 2xpart(element_offset);
251     if x.len > x.ww: $.dx = (x.len - x.w) / 2;
252     else: $.dx = xpart element_offset; fi;
253   else:
254     $.dx = xpart element_offset;
255   fi;
256 enddef;
257
258 vardef set_element_dy(suffix $) =
259   save y;
260   y.h = ypart(urcorner pic_$ - llcorner pic_$);
261   y.hh = y.h + 2ypart(element_offset);
262   if $.down: y := y.hh;
263   else:
264     y.maxport = max($.nin, $.nout);
265     y.len = y.maxport*port_length + (y.maxport-1)*port_sep + 2port_offset;
266     y := max(y.hh, y.len);
267   fi;
268   
269   y'' := min_element_height;
270   forever:
271     exitif y'' >= y;
272     y'' := y'' + element_height_increment;
273   endfor;
274   
275   $.dy = (y'' - y.h)/2;
276 enddef;
277
278 def sizeelement_(suffix $) =
279   if unknown $.dx: set_element_dx($); fi
280   if unknown $.dy: set_element_dy($); fi
281   if unknown $.borderscale: $.borderscale = defaultelementborderscale; fi
282   if unknown $.portscale: $.portscale = defaultelementportscale; fi
283 enddef;
284
285 vardef fixelementsizeleft(text t) =
286   forsuffixes $=t:
287     fixsize($);
288     if $.dx > xpart element_offset: $.off := $.off - ($.dx - xpart element_offset, 0); fi;
289   endfor;
290 enddef;
291
292 vardef fixelement(text elements) =
293   fixsize(elements);
294   fixpos(elements);
295 enddef;
296
297 vardef elementleftjustify(text elements) =
298   fixsize(elements);
299   forsuffixes $=elements:
300     if $.dx > xpart element_offset: $.off := $.off - ($.dx - xpart element_offset, 0); fi;
301   endfor;
302 enddef;
303
304 vardef fixrelations(suffix efirst)(text elements) =
305   forsuffixes $=elements:
306     if unknown xpart(efirst.off - $.off): xpart $.off = xpart efirst.off fi;
307     if unknown ypart(efirst.off - $.off): ypart $.off = ypart efirst.off fi;
308   endfor;
309 enddef;
310
311 vardef elementbbox(suffix efirst)(text elements) =
312   fixsize(efirst,elements);
313   fixrelations(efirst,elements);
314   save __t,__l,__r,__b,__p; picture __p;
315   __t = ypart(efirst.n - efirst.off);
316   __l = xpart(efirst.w - efirst.off);
317   __r = xpart(efirst.e - efirst.off);
318   __b = ypart(efirst.s - efirst.off);
319   forsuffixes $=elements:
320     if ypart($.n - efirst.off) > __t: __t := ypart($.n - efirst.off) fi;
321     if xpart($.w - efirst.off) < __l: __l := xpart($.w - efirst.off) fi;
322     if xpart($.e - efirst.off) > __r: __r := xpart($.e - efirst.off) fi;
323     if ypart($.s - efirst.off) < __b: __b := ypart($.s - efirst.off) fi;
324   endfor;
325   __p = nullpicture;
326   setbounds __p to ((__l,__t) -- (__r,__t) -- (__r,__b) -- (__l,__b) -- cycle)
327      if known efirst.off: shifted efirst.off fi;
328   __p
329 enddef;
330
331 vardef compoundelementlink@#(suffix efirst)(text elements) =
332   fixsize(efirst,elements);
333   fixrelations(efirst,elements);
334   save __t,__l,__r,__b,__p; picture __p;
335   __t = ypart(efirst.n - efirst.off);
336   __l = xpart(efirst.w - efirst.off);
337   __r = xpart(efirst.e - efirst.off);
338   __b = ypart(efirst.s - efirst.off);
339   forsuffixes $=elements:
340     if ypart($.n - efirst.off) > __t: __t := ypart($.n - efirst.off) fi;
341     if xpart($.w - efirst.off) < __l: __l := xpart($.w - efirst.off) fi;
342     if xpart($.e - efirst.off) > __r: __r := xpart($.e - efirst.off) fi;
343     if ypart($.s - efirst.off) < __b: __b := ypart($.s - efirst.off) fi;
344   endfor;
345   @#.c = efirst.off + .5[(__l,__t), (__r,__b)]
346 enddef;
347
348
349 %% draw
350
351 vardef draw_element_inputs(suffix $) =
352   path _p_, _ag_;
353   _p_ := _normal_input scaled $.portscale;
354   _ag_ := _agnostic_input scaled $.portscale;
355   if $.down: _p_ := _p_ rotated -90; _ag_ := _ag_ rotated -90; fi;
356   if $.rev: _p_ := _p_ rotated 180; _ag_ := _ag_ rotated 180; fi;
357   for _i_ = 0 upto $.nin - 1:
358     if $.inpers[_i_] >= 0:
359       fill _p_ shifted $.in[_i_] withcolor personalitycolor[$.inpers[_i_]];
360       draw _p_ shifted $.in[_i_];
361       if $.inpers[_i_] >= agnostic:
362         fill _ag_ shifted $.in[_i_] withcolor agnosticcolor[$.inpers[_i_]];
363         draw _ag_ shifted $.in[_i_]; fi
364     fi;
365   endfor
366 enddef;
367
368 vardef draw_element_outputs(suffix $) =
369   path _p_, _ag_;
370   _p_ := _normal_output scaled $.portscale;
371   _ag_ := _agnostic_output scaled $.portscale;
372   if $.down: _p_ := _p_ rotated -90; _ag_ := _ag_ rotated -90; fi;
373   if $.rev: _p_ := _p_ rotated 180; _ag_ := _ag_ rotated 180; fi;
374   for _i_ = 0 upto $.nout - 1:
375     if $.outpers[_i_] >= 0:
376       fill _p_ shifted $.out[_i_] withcolor personalitycolor[$.outpers[_i_]];
377       draw _p_ shifted $.out[_i_];
378       if $.outpers[_i_] >= agnostic:
379         fill _ag_ shifted $.out[_i_] withcolor agnosticcolor[$.outpers[_i_]];
380         draw _ag_ shifted $.out[_i_]; fi
381     fi;
382   endfor
383 enddef;
384
385 vardef drawelement(text elements) text rest =
386   drawelementbox(elements) rest;
387   drawunboxed(elements);
388 enddef;
389
390 vardef drawelementbox(text elements) text rest =
391   save $, oldpen; oldpen := savepen;
392   interim linejoin := mitered;
393   fixsize(elements);
394   fixpos(elements);
395   forsuffixes $ = elements:
396     if $.drawports:
397       pickup elementpen.port scaled $.portscale;
398       if $.nin > 0: draw_element_inputs($); fi;
399       if $.nout > 0: draw_element_outputs($); fi;
400     fi;
401     if $.borderscale > 0:
402       pickup elementpen.border scaled $.borderscale;
403       scantokens elemdraw_$($) rest;
404     fi;
405   endfor;
406   pickup oldpen;
407 enddef;
408
409 vardef fillelement(text elements)(text color) =
410   fixsize(elements);
411   fixpos(elements);
412   forsuffixes $=elements:
413     fill bpath.$ withcolor color;
414   endfor;
415 enddef;
416
417
418 %% queues
419
420 vardef _drawqueued(expr p,delta,rot,lim,pp) text rest =
421   save i; interim linecap := squared; i := delta;
422   forever:
423     draw (p) shifted ((i,0) rotated rot) withpen currentpen scaled 0.25 rest;
424     i := i + delta; exitunless i < lim;
425   endfor;
426   draw (pp) rest;
427 enddef;
428 def drawqueued(suffix $) =
429   _drawqueued($.ne -- $.se, 6, 180, .9*$.width, $.nw -- $.ne -- $.se -- $.sw)
430 enddef;
431 def drawrqueued(suffix $) =
432   _drawqueued($.nw -- $.sw, 6, 0, .9*$.width, $.ne -- $.nw -- $.sw -- $.se)
433 enddef;
434 def drawvqueued(suffix $) =
435   _drawqueued($.se -- $.sw, 5, 90, .9*$.height, $.nw -- $.sw -- $.se -- $.ne)
436 enddef;
437 def drawrvqueued(suffix $) =
438   _drawqueued($.ne -- $.nw, 5, 270, .9*$.height, $.sw -- $.nw -- $.ne -- $.se)
439 enddef;
440
441 vardef queueit@#(expr s) =
442   _elementit.@#(s, 1, 1, push_to_pull, false, false);
443   elemdraw_@# := "drawqueued";
444 enddef;
445 vardef rqueueit@#(expr s) =
446   _elementit.@#(s, 1, 1, push_to_pull, false, true);
447   elemdraw_@# := "drawrqueued";
448 enddef;
449 vardef vqueueit@#(expr s) =
450   _elementit.@#(s, 1, 1, push_to_pull, true, false);
451   elemdraw_@# := "drawvqueued";
452 enddef;
453 vardef rvqueueit@#(expr s) =
454   _elementit.@#(s, 1, 1, push_to_pull, true, true);
455   elemdraw_@# := "drawrvqueued";
456 enddef;
457
458
459 %% connections
460
461 picture _cutarrpic;
462
463 vardef arrowhead expr p =
464   save q,h,e,f; path q,h; pair e,f;
465   e = point length p of p;
466   q = gobble(p shifted -e cutafter makepath(pencircle scaled 2ahlength))
467     cuttings;
468   h = gobble(p shifted -e cutafter makepath(pencircle scaled 1.5ahlength))
469     cuttings;
470   f = point 0 of h;
471   (q rotated .5ahangle & reverse q rotated -.5ahangle -- f -- cycle)  shifted e
472 enddef;
473 def _cutarr(expr b,e) text t =
474   _cutarrpic := image(draw (0,0) -- (1,0) -- cycle t);
475   _cutarramt := (2ypart urcorner _cutarrpic / sind .5ahangle) - 0.75;
476   if _cutarramt > 0:
477     _apth := subpath (xpart(_apth intersectiontimes makepath(pencircle
478           scaled (b*_cutarramt)) shifted (point 0 of _apth)),
479       xpart(_apth intersectiontimes makepath(pencircle scaled (e*_cutarramt))
480   shifted (point length _apth of _apth))) of _apth;
481   fi
482 enddef;
483 def _finarr text t =
484   _cutarr(0,1) t;
485   draw (subpath (0, xpart(_apth intersectiontimes makepath(pencircle scaled 1.2ahlength) shifted (point length _apth of _apth))) of _apth) t;
486   fill arrowhead _apth  t
487 enddef;
488 def _findarr text t =
489   _cutarr(1,1) t;
490   draw (subpath
491     (xpart(_apth intersectiontimes makepath(pencircle scaled 1.2ahlength) shifted (point 0 of _apth)),
492      xpart(_apth intersectiontimes makepath(pencircle scaled 1.2ahlength) shifted (point length _apth of _apth))) of _apth) t;
493   fill arrowhead _apth  t;
494   fill arrowhead reverse _apth  t
495 enddef;
496
497 def connectpath(suffix $,#,##,$$) =
498   $.out[#]{$.flowvector} .. {$$.flowvector}$$.in[##]
499 enddef;
500 vardef drawconnectj(suffix $,#,##,$$)(text t) text rest =
501   interim linejoin := mitered;
502   drawarrow $.out[#]{$.flowvector} t {$$.flowvector}$$.in[##] withpen connectionpen rest
503 enddef;
504 def drawconnect(suffix $,#,##,$$) =
505   drawconnectj($,#,##,$$)(..)
506 enddef;
507 vardef drawconnectna(suffix $,#,##,$$) text rest =
508   interim linejoin := mitered;
509   draw $.out[#]{$.flowvector} .. {$$.flowvector}$$.in[##] withpen connectionpen rest
510 enddef;
511
512 def drawconnarrow expr p =
513   _apth:=p; _finarr withpen connectionpen
514 enddef;
515 def drawconnarrowna expr p =
516   draw p withpen connectionpen
517 enddef;
518 def drawdblconnarrow expr p =
519   _apth:=p; _findarr withpen connectionpen
520 enddef;