1use std::fs;
2use std::io::prelude::*;
4use std::io::BufWriter;
5use std::fs::File;
6use std::collections::HashMap;
7
8use adapton::engine::Name;
9use adapton::reflect::*;
10use labdef::{LabParams,Lab,LabResults, Sample};
12
13#[derive(Debug,Clone)]
26pub struct Div {
27 pub tag: String,
28 pub classes: Vec<String>,
29 pub extent: Box<Vec<Div>>,
30 pub text: Option<String>,
31}
32
33pub fn div_of_name (n:&Name) -> Div {
50 Div{ tag: String::from("name"),
51 classes: vec![ string_of_name(n) ],
54 extent: Box::new( vec![ ] ),
55 text: Some( format!("{}", string_of_name(n) ) ) }
56}
57
58pub fn div_of_path (p:&Path) -> Div {
59 Div{ tag: String::from("path"),
60 classes: vec![ ],
62 extent: Box::new(
63 p.iter().map( div_of_name ).collect()
64 ),
65 text: None }
66}
67
68pub fn div_of_loc (l:&Loc) -> Div {
69 Div{ tag: String::from("loc"),
70 classes: vec![ ],
73 extent: Box::new(vec![ div_of_path(&l.path), div_of_name(&l.name) ]),
74 text:None,
76 }
77}
78
79pub fn div_of_oploc (ol:&Option<Loc>) -> Div {
80 if true {
81 Div{ tag: String::from("oploc"),
82 classes: vec![],
83 extent: Box::new(vec![]),
84 text: None,
85 }
86 } else {
87 Div{ tag: String::from("oploc"),
88 classes: vec![],
89 extent: Box::new(match *ol {
90 None => vec![],
91 Some(ref l) => vec![ div_of_loc(l)]}),
92 text: None
93 }
94 }
95}
96
97pub fn div_of_succ (s:&Succ) -> Div {
98 Div{ tag: String::from("succ"),
99 classes: vec![
100 String::from(match s.effect {
101 Effect::Alloc => "succ-alloc",
102 Effect::Force => "succ-force"
103 }),
104 String::from(match s.dirty {
105 true => "succ-dirty",
106 false => "succ-not-dirty"
107 }),
108 ],
109 text: None,
110 extent: Box::new(vec![
111 div_of_loc(&s.loc),
112 ])}
113}
114
115pub fn div_of_edge (e:&trace::Edge) -> Div {
116 Div{ tag: String::from("edge"),
117 classes: vec![],
118 text: None,
119 extent: Box::new(
120 vec![ div_of_oploc(&e.loc),
121 div_of_succ(&e.succ) ]) }
122}
123
124pub fn div_of_value_tree (dcg:&DCG, visited:&mut HashMap<Loc, ()>, val:&Val) -> Div {
125 let div = Div {
126 tag: match *val {
127 Val::Constr(ref n, _) => { format!("val-constr constr-{}", string_of_name(n) ) },
128 Val::Struct(ref n, _) => { format!("val-struct struct-{}", string_of_name(n) ) },
129 Val::Const( ref c ) => { format!("val-const const-{}" , match *c {
130 Const::Nat( ref n ) => format!("{}", n),
131 Const::Num( ref n ) => format!("{}", n),
132 Const::String( ref s ) => s.clone(),
133 })},
134 Val::Tuple(ref vs) => { format!("val-tuple tuple-{}", vs.len()) },
135 Val::Vec(ref vs) => { format!("val-vec vec-{}", vs.len()) },
136 Val::Art(ref loc, _) => { format!("val-art {}", string_of_loc( loc ) ) },
137 Val::ValTODO => { format!("val-TODO") },
138 Val::Name(ref n) => { format!("name val-name {}", string_of_name(n)) },
139 },
140 classes: vec![],
141 text:
142 match *val {
143 Val::Constr(ref n, _) => { Some(string_of_name(n)) },
144 Val::Struct(ref n, _) => { Some(string_of_name(n)) },
145 Val::Const( ref c ) => Some(match *c {
146 Const::Nat( ref n ) => format!("{}", n),
147 Const::Num( ref n ) => format!("{}", n),
148 Const::String( ref s ) => format!("{:?}", s),
149 }),
150 Val::Tuple( _ ) => None,
151 Val::Vec( _ ) => None,
152 Val::ValTODO => None,
153 Val::Art( ref l, _ ) => {
154 Some(format!("{}", string_of_loc(l)))
155 }
156 Val::Name(ref n) => {
157 Some(format!("{}", string_of_name(n)))
158 }
159 },
160
161 extent: Box::new(
162 match *val {
163 Val::Constr(_, ref vs) => { let ds : Vec<_> = vs.iter().map( |v| div_of_value_tree(dcg, visited, v) ).collect() ; ds },
164 Val::Struct(_, ref fs) => { let ds : Vec<_> = fs.iter().map( |&(ref _f, ref v) |
165 div_of_value_tree(dcg, visited, &v) ).collect() ; ds },
166 Val::Tuple(ref vs) => { let ds : Vec<_> = vs.iter().map( |v| div_of_value_tree(dcg, visited, v) ).collect() ; ds },
167 Val::Vec(ref vs) => { let ds : Vec<_> = vs.iter().map( |v| div_of_value_tree(dcg, visited, v) ).collect() ; ds },
168 Val::Const( _ ) => vec![],
169 Val::ValTODO => vec![],
170 Val::Name(_) => vec![],
171 Val::Art( ref l, _ ) => vec![
172 div_of_loc(l),
173 match dcg.table.get(l) {
174 None => Div{ tag: String::from("dangling"),
175 classes:vec![String::from("no-extent")],
176 text:Some(String::from("Dangling")),
177 extent:Box::new(vec![]),
178 },
179 Some(node) => {
180 match *node {
181 Node::Pure(ref p) => div_of_value_tree(dcg, visited, &p.value),
182 Node::Ref(ref n) => div_of_value_tree(dcg, visited, &n.value),
183 Node::Comp(ref n) => match n.value {
184 None =>
185 Div{ tag: String::from("Unevald"),
186 classes:vec![String::from("no-extent")],
187 text:Some(String::from("Uneval'd")),
188 extent:Box::new(vec![]),
189 },
190 Some(ref v) => div_of_value_tree(dcg, visited, v),
191 }
192 }
193 }
194 }
195 ],
196 }
197 )
198 }
199 ;
200 div
201}
202
203pub fn div_of_force_tree (dcg:&DCG, visited:&mut HashMap<Loc, ()>, loc:&Loc) -> Div {
204 let mut div = Div {
205 tag:String::from("force-tree"),
206 text:None,
207 classes: vec![],
208 extent: Box::new(vec![ div_of_loc( loc ) ]),
209 };
210 visited.insert( loc.clone(), () );
211 let no_extent = match dcg.table.get( loc ) {
212 None => panic!("dangling pointer in reflected DCG!"),
213 Some( nd ) => {
214 match succs_of_node( nd ) {
215 None => true, Some( succs ) => {
217 let mut no_extent = true;
218 for succ in succs {
219 if succ.effect == Effect::Force {
220 no_extent = false;
221 let succ_div = div_of_force_tree (dcg, visited, &succ.loc);
222 div.extent.push( succ_div )
223 }
224 };
225 no_extent
226 }
227 }
228 }
229 };
230 if no_extent {
231 div.classes.push(String::from("no-extent"))
232 };
233 div
234}
235
236pub fn div_of_alloc_tree (dcg:&DCG, visited:&mut HashMap<Loc, ()>, loc:&Loc) -> Div {
237 let mut div = Div {
238 tag:String::from("alloc-tree"),
239 text:None,
240 classes: vec![],
241 extent: Box::new(vec![ div_of_loc( loc ) ]),
242 };
243 visited.insert( loc.clone(), () );
244 let no_extent = match dcg.table.get( loc ) {
245 None => panic!("dangling pointer in reflected DCG!"),
246 Some( nd ) => {
247 match succs_of_node( nd ) {
248 None => true, Some( succs ) => {
250 let mut no_extent = true;
251 for succ in succs {
252 if succ.effect == Effect::Alloc {
253 no_extent = false;
254 let succ_div = div_of_alloc_tree (dcg, visited, &succ.loc);
255 div.extent.push( succ_div )
256 }
257 };
258 no_extent
259 }
260 }
261 }
262 };
263 if no_extent {
264 div.classes.push(String::from("no-extent"))
265 };
266 div
267}
268
269
270pub fn class_of_dcg_node (nd:&Node) -> String {
271 match *nd {
272 Node::Comp(_) => String::from("dcg-node-comp"),
273 Node::Ref(_) => String::from("dcg-node-ref"),
274 Node::Pure(_) => String::from("dcg-node-pure"),
275 }
276}
277
278pub fn div_of_dcg_alloc_edge (src:Option<&Loc>, loc:&Loc, nd:&Node, is_dirty:bool) -> Div {
279 let div = Div {
280 tag:String::from("dcg-alloc-edge"),
281 text:None,
282 classes: vec![ if is_dirty { String::from("dirty") } else { String::from("clean") },
283 if src == None { String::from("editor-edge") } else { String::from("dcg-edge") },
284 class_of_dcg_node( nd ) ],
285 extent: Box::new(vec![ div_of_loc( loc ) ]),
286 };
287 div
288}
289
290pub fn div_of_dcg_succs (dcg:&DCG, visited:&mut HashMap<Loc, ()>, loc:Option<&Loc>,
291 succs: &Vec<Succ>,
292 extent: &mut Vec<Div>) {
293 for succ in succs {
294 match succ.effect {
295 Effect::Alloc => {
296 let node = dcg.table.get( &succ.loc ).unwrap();
297 let succ_div = div_of_dcg_alloc_edge (loc, &succ.loc, &node, succ.dirty);
298 extent.push( succ_div )
299 },
300 Effect::Force => {
301 let succ_div = div_of_dcg_force_edge (loc, dcg, visited, &succ.loc, succ.dirty, succ.is_dup);
302 extent.push( succ_div )
303 }
304 }
305 }
306}
307
308pub fn div_of_dcg_force_edge (src:Option<&Loc>, dcg:&DCG, visited:&mut HashMap<Loc, ()>,
309 loc:&Loc, is_dirty:bool, is_dup:bool) -> Div
310{
311 let mut div = Div {
312 tag:String::from("dcg-force-edge"),
313 text:None,
314 classes: vec![
315 if is_dup { String::from("dup-edge") } else { String::from("not-dup-edge") },
316 if is_dirty { String::from("dirty") } else { String::from("clean") },
317 if src == None { String::from("editor-edge") } else { String::from("dcg-edge") },
318 ],
319 extent: Box::new(vec![ div_of_loc( loc ) ]),
320 };
321 visited.insert( loc.clone(), () );
322 let no_extent = match dcg.table.get( loc ) {
323 None => panic!("dangling pointer in reflected DCG!"),
324 Some( nd ) => {
325 div.classes.push( class_of_dcg_node(nd) );
326 match succs_of_node( nd ) {
327 None => true, Some( succs ) => {
329 div_of_dcg_succs(dcg, visited, Some(loc), succs, &mut div.extent);
330 false
331 }
332 }
333 }
334 };
335 if no_extent {
336 div.classes.push(String::from("no-extent"))
337 };
338 div
339}
340
341pub fn div_of_trace (tr:&trace::Trace) -> Div {
342 let tr_eff_url = "http://adapton.org/rustdoc/adapton/engine/reflect/trace/enum.Effect.html";
344
345 let mut div =
346 Div{
347 tag: String::from("trace"),
348 text: None,
349 classes: vec![
350 String::from(match tr.effect {
351 trace::Effect::CleanRec => "tr-clean-rec",
352 trace::Effect::CleanEval => "tr-clean-eval",
353 trace::Effect::CleanEdge => "tr-clean-edge",
354 trace::Effect::Dirty => "tr-dirty",
355 trace::Effect::Remove => "tr-remove",
356 trace::Effect::Alloc(trace::AllocCase::LocFresh,_) => "tr-alloc-loc-fresh",
357 trace::Effect::Alloc(trace::AllocCase::LocExists(trace::ChangeFlag::ContentSame),_) => "tr-alloc-loc-exists-same",
358 trace::Effect::Alloc(trace::AllocCase::LocExists(trace::ChangeFlag::ContentDiff),_) => "tr-alloc-loc-exists-diff",
359 trace::Effect::Force(_) if tr.edge.succ.is_dup => "tr-force-dup",
360 trace::Effect::Force(trace::ForceCase::CompCacheMiss) => "tr-force-compcache-miss",
361 trace::Effect::Force(trace::ForceCase::CompCacheHit) => "tr-force-compcache-hit",
362 trace::Effect::Force(trace::ForceCase::RefGet) => "tr-force-refget",
363 })
364 ],
365 extent: Box::new(
366 vec![
367 Div{
368 tag: String::from("tr-effect"),
369 text: Some(
370 format!("<a href={:?}>{}</a>", tr_eff_url, match tr.effect {
371 trace::Effect::CleanRec => "CleanRec",
372 trace::Effect::CleanEval => "CleanEval",
373 trace::Effect::CleanEdge => "CleanEdge",
374 trace::Effect::Dirty => "Dirty",
375 trace::Effect::Remove => "Remove",
376 trace::Effect::Alloc(trace::AllocCase::LocFresh,_) => "Alloc(LocFresh)",
377 trace::Effect::Alloc(trace::AllocCase::LocExists(trace::ChangeFlag::ContentSame),_) => "Alloc(LocExists(SameContent))",
378 trace::Effect::Alloc(trace::AllocCase::LocExists(trace::ChangeFlag::ContentDiff),_) => "Alloc(LocExists(DiffContent))",
379 trace::Effect::Force(_) if tr.edge.succ.is_dup => "ForceDup",
380 trace::Effect::Force(trace::ForceCase::CompCacheMiss) => "Force(CompCacheMiss)",
381 trace::Effect::Force(trace::ForceCase::CompCacheHit) => "Force(CompCacheHit)",
382 trace::Effect::Force(trace::ForceCase::RefGet) => "Force(RefGet)",
383 })),
384 classes: vec![],
385 extent: Box::new(vec![]),
386 },
387 Div{
388 tag: String::from("tr-symbols"),
389 text: match tr.effect {
390 trace::Effect::Alloc(_,trace::AllocKind::RefCell) => Some(String::from("▣")),
391 trace::Effect::Alloc(_,trace::AllocKind::Thunk) => Some(String::from("◯")),
392 _ => None,
393 },
394 classes:vec![],
395 extent: Box::new(vec![]),
396 },
397 match (tr.effect.clone(), tr.edge.loc.clone()) {
402 (trace::Effect::CleanEval, Some(loc)) => div_of_loc(&loc),
403 _ => div_of_edge(&tr.edge)
405 }
406 ])}
407 ;
408 match tr.effect {
409 trace::Effect::Alloc(_,trace::AllocKind::RefCell) => div.classes.push(String::from("alloc-kind-refcell")),
410 trace::Effect::Alloc(_,trace::AllocKind::Thunk) => div.classes.push(String::from("alloc-kind-thunk")),
411 _ => ()
412 };
413 if tr.extent.len() > 0 {
414 div.classes.push( String::from("has-extent") );
415 div.extent.push(
416 Div{ tag: String::from("tr-extent"),
417 text: None,
418 classes: vec![],
419 extent:
420 Box::new(tr.extent.iter().map(div_of_trace).collect())
421 }
422 )
423 } else {
424 div.classes.push( String::from("no-extent") );
425 };
426 return div
427}
428
429pub trait WriteHTML {
430 fn write_html<Wr:Write>(&self, wr: &mut Wr);
431}
432
433impl WriteHTML for Div {
434 fn write_html<Wr:Write>(&self, wr: &mut Wr) {
435 writeln!(wr, "<div class=\"{} {}\">",
436 self.tag,
437 self.classes.iter().fold(
438 String::new(),
439 |mut cs,c|{cs.push_str(" ");
440 cs.push_str(c.as_str()); cs}
441 )
442 ).unwrap();
443 match self.text {
444 None => (),
445 Some(ref text) => writeln!(wr, "{}", text).unwrap()
446 };
447 for div in self.extent.iter() {
448 div.write_html(wr);
449 };
450 writeln!(wr, "</div>").unwrap();
451 }
452}
453
454impl<T:WriteHTML> WriteHTML for Vec<T> {
455 fn write_html<Wr:Write>(&self, wr:&mut Wr) {
456 for x in self.iter() {
457 x.write_html(wr);
458 }
459 }
460}
461
462pub fn write_lab_results_summary
463 (_params:&LabParams,
464 labs:&Vec<Box<Lab>>,
465 results:&Vec<LabResults>)
466{
467 fs::create_dir_all("lab-results").unwrap();
469 let f = File::create(format!("lab-results/index.html")).unwrap();
470 let mut writer = BufWriter::new(f);
471
472 writeln!(writer, "{}", style_string()).unwrap();
473 writeln!(writer, "<style> .tool-label-toggles {{ display: none }} </style>").unwrap();
474
475 assert!( labs.len() == results.len() );
476
477 writeln!(writer, "<div class={:?}>Lab results summary</div>", "labsum-title").unwrap();
478
479 for ((_i,lab),(_j,_result)) in
480 labs.iter().enumerate().zip(results.iter().enumerate())
481 {
482 writeln!(&mut writer, "<div class={:?}>", "labsum-row").unwrap();
483 writeln!(&mut writer, "<div class={:?}>", "labsum-name").unwrap();
484 write_lab_name(&mut writer, lab, false);
485 writeln!(&mut writer, "</div>").unwrap();
486
487 writeln!(&mut writer, "<a class={:?} href=./{}/index.html>detailed results</a>",
488 "lab-details",
489 string_of_name(&lab.name())
490 ).unwrap();
491
492 writeln!(&mut writer, "</div>").unwrap();
493 write_cr(&mut writer);
494 }
495}
496
497pub fn write_cr<W:Write>(writer:&mut W) {
498 writeln!(writer, "<hr/>").unwrap();
500}
501
502pub fn write_lab_name<W:Write>(writer:&mut W, lab:&Box<Lab>, is_title:bool) {
503 let catalog_url = String::from("http://adapton.org/rustdoc/adapton_lab/catalog/index.html");
504
505 let labname = string_of_name( &lab.name() );
506 let laburl = lab.url();
507
508 writeln!(writer, "<div class={:?}><a href={:?} class={:?}>{}</a></div>",
509 "lab-name",
510 match *laburl {
511 Some(ref url) => url,
512 None => & catalog_url
513 },
514 format!("lab-name {}", if is_title { "page-title" } else { "" }),
515 labname
516 ).unwrap();
517}
518
519pub fn write_dcg_tree<W:Write> (writer:&mut W, dcg:&DCG, traces:&Vec<trace::Trace>) {
520 let mut visited = HashMap::new();
521 let mut extent : Vec<_> = Vec::new();
522 let succs : Vec<_> = traces.iter().map(|t| t.edge.succ.clone()).collect();
523 div_of_dcg_succs(dcg, &mut visited, None, &succs, &mut extent);
524 for d in extent.iter() {
525 d.write_html(writer);
526 }
527}
528
529pub fn write_dcg_edge_tree<W:Write> (writer:&mut W, dcg:&DCG, traces:&Vec<trace::Trace>, effect:Effect) {
530 for tr in traces.iter() {
531 if tr.edge.succ.effect == effect {
532 match effect {
533 Effect::Alloc =>
534 div_of_alloc_tree(dcg, &mut HashMap::new(), &tr.edge.succ.loc)
535 .write_html(writer),
536 Effect::Force =>
537 div_of_force_tree(dcg,&mut HashMap::new(), &tr.edge.succ.loc)
538 .write_html(writer),
539 }
540 }
541 }
542}
543
544pub fn write_sample_dcg<W:Write>
545 (writer:&mut W,
546 _lab:&Box<Lab>,
547 prev_sample:Option<&Sample>,
548 this_sample:&Sample)
549{
550 write_cr(writer)
551 ;
552 match this_sample.dcg_sample.process_input.reflect_dcg {
553 None => { },
554 Some(ref dcg_post_edit) => {
555 match this_sample.dcg_sample.input {
556 None => { },
557 Some(ref input) => {
558 writeln!(writer, "<div class=\"input-value\">").unwrap();
559 writeln!(writer, "<div class=\"label\">{}</div>", "Input:").unwrap();
560 div_of_value_tree(dcg_post_edit, &mut HashMap::new(), input)
561 .write_html( writer );
562 writeln!(writer, "</div>").unwrap();
563 }
564 }
565 }
566 }
567 ;
568 match this_sample.dcg_sample.compute_output.reflect_dcg {
569 None => { },
570 Some(ref dcg_post_update) => {
571 match this_sample.dcg_sample.output {
572 None => { },
573 Some(ref output) => {
574 writeln!(writer, "<div class=\"output-value\">").unwrap();
575 writeln!(writer, "<div class=\"label\">{}</div>", "Output:").unwrap();
576 div_of_value_tree(dcg_post_update, &mut HashMap::new(), output)
577 .write_html( writer );
578 writeln!(writer, "</div>").unwrap();
579 }
580 }
581 }
582 }
583 ;
584 write_cr(writer);
586 ;
587 match this_sample.dcg_sample.process_input.reflect_dcg {
588 Some(ref dcg_post_edit) => {
589 match prev_sample {
590 Some(ref prev_sample) => {
591
592 writeln!(writer, "<div class=\"archivist-dcg-tree-post-edit\">").unwrap();
594 writeln!(writer, "<div class=\"label\">{}</div>", "DCG, post-edit:").unwrap();
595 write_dcg_tree
596 (writer,
597 dcg_post_edit,
598 &prev_sample.dcg_sample.compute_output.reflect_traces,
599 );
600 writeln!(writer, "</div>").unwrap();
601
602 if false {
603 writeln!(writer, "<div class=\"archivist-alloc-tree-post-edit\">").unwrap();
605 writeln!(writer, "<div class=\"label\">{}</div>", "Allocs, post-edit:").unwrap();
606 write_dcg_edge_tree
607 (writer,
608 dcg_post_edit,
609 &prev_sample.dcg_sample.compute_output.reflect_traces,
610 Effect::Alloc
611 );
612 writeln!(writer, "</div>").unwrap();
613
614 writeln!(writer, "<div class=\"archivist-force-tree-post-edit\">").unwrap();
616 writeln!(writer, "<div class=\"label\">{}</div>", "Forces, post-edit:").unwrap();
617 write_dcg_edge_tree
618 (writer,
619 dcg_post_edit,
620 &prev_sample.dcg_sample.compute_output.reflect_traces,
621 Effect::Force,
622 );
623 writeln!(writer, "</div>").unwrap();
624 }
625
626 },
627 _ => {
628 writeln!(writer,"<div class=\"archivist-alloc-tree-post-edit\"></div>").unwrap();
629 writeln!(writer,"<div class=\"archivist-force-tree-post-edit\"></div>").unwrap();
630 }}
631 },
632 _ => {
633 }
636 }
637 ;
638 writeln!(writer,"<div class=\"archivist-update-sep\"></div>").unwrap();
639
640 match this_sample.dcg_sample.compute_output.reflect_dcg {
641 Some(ref dcg_post_update) => {
642
643 writeln!(writer, "<div class=\"archivist-dcg-tree-post-update\">").unwrap();
645 writeln!(writer, "<div class=\"label\">{}</div>", "DCG, post-compute:").unwrap();
646 write_dcg_tree
647 (writer,
648 dcg_post_update,
649 &this_sample.dcg_sample.compute_output.reflect_traces,
650 );
651 writeln!(writer, "</div>").unwrap();
652
653 if false {
654 writeln!(writer, "<div class=\"archivist-alloc-tree-post-update\">").unwrap();
656 writeln!(writer, "<div class=\"label\">{}</div>", "Allocs, post-update:").unwrap();
657 write_dcg_edge_tree
658 (writer,
659 dcg_post_update,
660 &this_sample.dcg_sample.compute_output.reflect_traces,
661 Effect::Alloc
662 );
663 writeln!(writer, "</div>").unwrap();
664
665 writeln!(writer, "<div class=\"archivist-force-tree-post-update\">").unwrap();
667 writeln!(writer, "<div class=\"label\">{}</div>", "Forces, post-update:").unwrap();
668 write_dcg_edge_tree
669 (writer,
670 dcg_post_update,
671 &this_sample.dcg_sample.compute_output.reflect_traces,
672 Effect::Force,
673 );
674 writeln!(writer, "</div>").unwrap();
675 }
676
677 write_cr(writer);
678 },
679 _ => {
680 }
683 };
684
685}
686
687pub fn write_lab_results(params:&LabParams, lab:&Box<Lab>, results:&LabResults) {
688
689 let write_times = if params.sample_params.reflect_trace { false } else { true };
693
694 let labname = string_of_name( &lab.name() );
695 fs::create_dir_all(format!("lab-results/{}/", labname)).unwrap();
702 let f = File::create(format!("lab-results/{}/index.html", labname)).unwrap();
703 let mut writer = BufWriter::new(f);
704 writeln!(writer, "{}", style_string()).unwrap();
705 writeln!(writer, "<a href=\"../index.html\">↰ Results summary</a>").unwrap();
706 write_cr(&mut writer);
707 write_lab_name(&mut writer, lab, true);
708 writeln!(writer, "<div style=\"font-size:12px\" class=\"batch-name\"> step</div>").unwrap();
709 if write_times {
710 writeln!(writer, "<div style=\"font-size:20px\" class=\"editor\">Editor</div>").unwrap();
711 writeln!(writer, "<div style=\"font-size:20px\" class=\"archivist\">Archivist</div>").unwrap();
712 }
713 let mut prev_sample = None;
714 for sample in results.samples.iter() {
715 write_cr(&mut writer);
716 writeln!(writer, "<div class=\"batch-name-lab\">batch name<div class=\"batch-name\">{:?}</div></div>",
719 sample.batch_name).unwrap();
720
721 if write_times {
722 writeln!(writer, "<div class=\"editor\">").unwrap();
723
724 writeln!(writer, "<div class=\"time-ns-lab\">time (ns): <div class=\"time-ns\">{:?}</div></div>",
725 sample.dcg_sample.process_input.time_ns).unwrap();
726 writeln!(writer, "</div>").unwrap();
727
728 writeln!(writer, "<div class=\"archivist\">").unwrap();
729
730 writeln!(writer, "<div class=\"row\">").unwrap();
731
732 writeln!(writer, "<div class=\"time-ns-lab\">Naive time (ns): <div class=\"time-ns\">{:?}</div></div>",
733 sample.naive_sample.compute_output.time_ns).unwrap();
734
735 writeln!(writer, "<div class=\"time-ms-lab\">Naive time (ms): <div class=\"time-ms\">{:.*}</div></div>",
736 2, (sample.naive_sample.compute_output.time_ns as f64) / (1000_000 as f64)).unwrap();
737 writeln!(writer, "</div>").unwrap();
738
739 writeln!(writer, "<div class=\"row\">").unwrap();
740 writeln!(writer, "<div class=\"time-ns-lab\">DCG time (ns): <div class=\"time-ns\">{:?}</div></div>",
741 sample.dcg_sample.compute_output.time_ns).unwrap();
742
743 writeln!(writer, "<div class=\"time-ms-lab\">DCG time (ms): <div class=\"time-ms\">{:.*}</div></div>",
744 2, (sample.dcg_sample.compute_output.time_ns as f64) / (1000_000 as f64)).unwrap();
745 writeln!(writer, "</div>").unwrap();
746
747 if sample.naive_sample.compute_output.time_ns <
748 sample.dcg_sample.compute_output.time_ns {
749 writeln!(writer, "<div class=\"overhead-lab\">DCG Overhead: <div class=\"overhead\">{:.*}</div></div>",
750 2, ( (sample.dcg_sample.compute_output.time_ns as f64) /
751 (sample.naive_sample.compute_output.time_ns as f64) )).unwrap();
752 } else {
753 writeln!(writer, "<div class=\"speedup-lab\">DCG Speedup: <div class=\"speedup\">{:.*}</div></div>",
754 2, ( (sample.naive_sample.compute_output.time_ns as f64) /
755 (sample.dcg_sample.compute_output.time_ns as f64) )).unwrap();
756 }
757
758 writeln!(writer, "</div>").unwrap();
759 write_cr(&mut writer);
760 }
761
762 write_sample_dcg(&mut writer, lab, prev_sample, sample);
767
768 if sample.dcg_sample.compute_output.reflect_traces.len() == 0 {
769 } else {
771 writeln!(writer, "<div class=\"traces-box\">").unwrap();
775 writeln!(writer, "<div class=\"label\">{}</div>", "Editor trace:").unwrap();
779 writeln!(writer, "<div class=\"traces\">").unwrap();
780 for tr in sample.dcg_sample.process_input.reflect_traces.iter() {
781 div_of_trace(tr).write_html(&mut writer)
782 }
783 writeln!(writer, "</div>").unwrap();
784 writeln!(writer, "</div>").unwrap();
785
786 writeln!(writer, "<div class=\"traces-box\">").unwrap();
791 writeln!(writer, "<div class=\"label\">{}</div>", "Archivist trace:").unwrap();
792 writeln!(writer, "<div class=\"traces\">").unwrap();
793 for tr in sample.dcg_sample.compute_output.reflect_traces.iter() {
794 div_of_trace(tr).write_html(&mut writer)
795 }
796 writeln!(writer, "</div>").unwrap();
797 writeln!(writer, "</div>").unwrap();
798 write_cr(&mut writer);
799 }
800
801 prev_sample = Some(sample) ; }
804 writer.flush().unwrap();
805}
806
807pub fn style_string() -> &'static str {
808"
809<html>
810<head>
811<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js\"></script>
812
813<style>
814div {
815 display: inline
816}
817body {
818 display: inline;
819 color: #aa88cc;
820 background: #552266;
821 font-family: sans-serif;
822 text-decoration: none;
823 padding: 0px;
824 margin: 0px;
825}
826body:visited {
827 color: #aa88cc;
828}
829a {
830 text-decoration: none;
831}
832a:hover {
833 text-decoration: underline;
834}
835hr {
836 display: block;
837 float: left;
838 clear: both;
839 width: 0px;
840 border: none;
841}
842
843.lab-name {
844 color: #ccaadd;
845 margin: 1px;
846 padding: 1px;
847}
848.lab-name:visited {
849 color: #ccaadd;
850}
851.lab-name:hover {
852 color: white;
853}
854
855.row {
856 display: block;
857}
858
859.labsum-title {
860 display: block;
861 margin: 8px;
862 font-size: 20px;
863}
864.labsum-row {
865 display: block;
866}
867.labsum-name {
868 display: table-cell;
869 margin: 8px;
870 padding: 2px;
871 width: 70%;
872}
873.lab-details {
874 display: table-cell;
875 font-size: 14px;
876 color: #ddbbee;
877 border: solid white 1px;
878 padding: 2px;
879 background-color: #441155;
880 margin: 3px;
881}
882
883.batch-name-lab {
884 font-size: 0px;
885 color: black;
886}
887.batch-name {
888 color: black;
889 font-size: 16px;
890 border: solid;
891 display: inline;
892 padding: 3px;
893 margin: 3px;
894 float: left;
895 background: #aa88aa;
896 width: 32px;
897}
898.time-ns {
899 font-size: 12px;
900 display: inline;
901}
902.time-ms {
903 font-size: 20px;
904 display: inline;
905}
906.overhead {
907 font-size: 30px;
908 display: inline;
909 color: #880000;
910 background: #ffcccc;
911 border: solid 1px red;
912}
913.speedup {
914 font-size: 30px;
915 display: inline;
916 color: #008800;
917 background: #ccffcc;
918 border: solid 1px green;
919}
920.time-ms {
921 font-size: 20px;
922 display: inline;
923}
924.editor {
925 color: black;
926 font-size: 14px;
927 border: solid;
928 display: block;
929 padding: 1px;
930 margin: 1px;
931 float: left;
932 width: 10%;
933 background: #aaaaaa;
934}
935.archivist {
936 color: black;
937 font-size: 14px;
938 border: solid;
939 display: block;
940 padding: 1px;
941 margin: 1px;
942 float: left;
943 width: 85%;
944 background: #dddddd;
945}
946.traces {
947 color: black;
948 font-size: 8px;
949 border: solid 0px;
950 display: block;
951 margin: 0px;
952 float: left;
953 width: 100%;
954}
955.traces:visited {
956 color: black;
957}
958
959.input-value,
960.output-value,
961.archivist-dcg-tree-post-edit,
962.archivist-dcg-tree-post-update,
963.traces-box,
964.archivist-alloc-tree-post-edit,
965.archivist-force-tree-post-edit,
966.archivist-alloc-tree-post-update,
967.archivist-force-tree-post-update
968{
969 display: inline;
970 float: left;
971
972 padding: 0px;
973 margin: 2px;
974
975 color: #dd88ff;
976 background: #331144;
977 border-radius: 5px;
978 border-style: solid;
979 border-width: 0px;
980 border-color: #dd88ff;
981}
982
983.input-value,
984.output-value {
985 width: 49%;
986}
987.traces-box {
988 width: 99%;
989}
990.archivist-dcg-tree-post-edit,
991.archivist-dcg-tree-post-update {
992 width: 49%;
993}
994.archivist-alloc-tree-post-edit,
995.archivist-force-tree-post-edit,
996.archivist-alloc-tree-post-update,
997.archivist-force-tree-post-update {
998 width: 24%;
999}
1000.tool-label-toggles {
1001 display: block;
1002 float: right;
1003}
1004
1005
1006.trace, .force-tree, .alloc-tree, .dcg-alloc-edge, .dcg-force-edge {
1007 color: black;
1008 display: inline-block;
1009 border-style: solid;
1010 border-color: red;
1011 border-width: 1px;
1012 font-size: 0px;
1013 padding: 0px;
1014 margin: 1px;
1015 border-radius: 5px;
1016}
1017
1018.dcg-force-edge {
1019 border-color: blue;
1020 border-width: 1px;
1021}
1022.dcg-node-comp {
1023 background: #ccccff;
1024 padding: 0px;
1025}
1026.dcg-node-ref {
1027 border-radius: 0px;
1028}
1029.dcg-alloc-edge {
1030 border-color: green;
1031 background: #ccffcc;
1032 border-width: 1px;
1033 padding: 3px;
1034}
1035.dirty {
1036 border-width: 2px;
1037 border-color: red;
1038 background: #ffcccc;
1039}
1040.editor-edge {
1041 border-width: 2px;
1042 border-color: black;
1043}
1044
1045.tr-effect {
1046 display: inline;
1047 display: none;
1048 font-size: 10px;
1049 background-color: white;
1050 border-radius: 2px;
1051}
1052.tr-symbols {
1053 font-size: 10px;
1054 display: inline;
1055 display: none;
1056}
1057
1058.path {
1059 display: inline-block;
1060 display: none;
1061
1062 margin: 0px;
1063 padding: 1px;
1064 border-radius: 1px;
1065 border-style: solid;
1066 border-width: 1px;
1067 border-color: #664466;
1068 background-color: #664466;
1069}
1070
1071.alloc-kind-thunk {
1072 border-color: green;
1073 border-radius:20px;
1074}
1075.alloc-kind-refcell {
1076 border-color: green;
1077 border-radius:0;
1078}
1079.tr-force-compcache-miss {
1080 background: #ccccff;
1081 border-color: blue;
1082 padding: 0px;
1083}
1084.tr-force-compcache-hit {
1085 background: #ccccff;
1086 border-color: blue;
1087 border-width: 4px;
1088 padding: 3px;
1089}
1090.tr-force-refget {
1091 border-radius: 0;
1092 border-color: blue;
1093}
1094.tr-force-dup {
1095 border-width: 0px;
1096 padding: 0px;
1097 background: #666666;
1098 display: none;
1099}
1100.tr-clean-rec {
1101 background: #222244;
1102 border-color: #aaaaff;
1103 border-width: 1px;
1104}
1105.tr-clean-eval {
1106 background: #8888ff;
1107 border-color: white;
1108 border-width: 4px;
1109}
1110.tr-clean-edge {
1111 background: white;
1112 border-color: #aaaaff;
1113 border-width: 2px;
1114 padding: 3px;
1115}
1116.tr-alloc-loc-fresh {
1117 padding: 3px;
1118 background: #ccffcc;
1119}
1120.tr-alloc-loc-exists-same {
1121 padding: 3px;
1122 background: #ccffcc;
1123 border-width: 4px;
1124 border-color: green;
1125}
1126.tr-alloc-loc-exists-diff {
1127 padding: 3px;
1128 background: #ffcccc;
1129 border-width: 4px;
1130 border-color: red;
1131}
1132.tr-dirty {
1133 background: #550000;
1134 border-color: #ffaaaa;
1135 border-width: 1px;
1136}
1137.tr-remove {
1138 background: red;
1139 border-color: black;
1140 border-width: 2px;
1141 padding: 2px;
1142}
1143
1144.force-tree {
1145 background: #ccccff;
1146 border-color: blue;
1147}
1148.alloc-tree {
1149 background: #ccffcc;
1150 border-color: green;
1151}
1152
1153.no-extent {
1154 padding: 3px;
1155}
1156.page-title {
1157 display: block;
1158 font-size: 32px;
1159 color: #ccaadd;
1160 margin: 8px;
1161}
1162
1163.val-name,
1164.val-constr,
1165.val-struct,
1166.val-tuple,
1167.val-vec,
1168.val-art
1169{
1170 display: inline-block;
1171 border-style: solid;
1172 border-width: 1px;
1173 border-color: #dd88ff;
1174 background-color: #220033;
1175 padding: 1px;
1176 margin: 1px;
1177 border-radius 2px;
1178 font-size: 0px;
1179}
1180.val-constr,
1181.val-struct,
1182.val-tuple,
1183.val-vec {
1184 border-color: #dd88ff;
1185 background-color: #773388;
1186}
1187.val-art
1188{
1189 padding: 2px;
1190}
1191
1192.name {
1193 display: inline;
1194 display: none;
1195
1196 font-size: 9px;
1197 color: black;
1198 background: white;
1199 border-style: solid;
1200 border-width: 1px;
1201 border-color: #664466;
1202 border-radius: 2px;
1203 padding: 1px;
1204 margin: 1px;
1205}
1206
1207.val-const
1208{
1209 display: inline-block;
1210 border-style: solid;
1211 border-color: black;
1212 border-width: 1px;
1213 color: black;
1214 background-color: grey;
1215 padding: 2px;
1216 margin: 1px;
1217 border-radius 5px;
1218 font-size: 8px;
1219}
1220
1221</style>
1222
1223<script>
1224function togglePaths() {
1225 var selection = document.getElementById(\"checkbox-1\");
1226 if (selection.checked) {
1227 $('.path').css('display', 'inline-block')
1228 } else {
1229 $('.path').css('display', 'none')
1230 }
1231}
1232
1233function toggleNames() {
1234 var selection = document.getElementById(\"checkbox-2\");
1235 if (selection.checked) {
1236 $('.name').css('display', 'inline')
1237 } else {
1238 $('.name').css('display', 'none')
1239 }
1240}
1241
1242function toggleEffects() {
1243 var selection = document.getElementById(\"checkbox-3\");
1244 if (selection.checked) {
1245 $('.tr-effect').css('display', 'inline')
1246 } else {
1247 $('.tr-effect').css('display', 'none')
1248 }
1249}
1250
1251function toggleDupForces() {
1252 var selection = document.getElementById(\"checkbox-4\");
1253 if (selection.checked) {
1254 $('.tr-force-dup').css('display', 'inline')
1255 } else {
1256 $('.tr-force-dup').css('display', 'none')
1257 }
1258}
1259</script>
1260</head>
1261
1262<body>
1263
1264<fieldset class=\"tool-label-toggles\">
1265 <legend>Toggle labels: </legend>
1266 <label for=\"show-paths-checkbox\">paths</label>
1267 <input type=\"checkbox\" name=\"show-paths-checkbox\" id=\"checkbox-1\" onchange=\"togglePaths()\">
1268 <label for=\"show-names-checkbox\">names</label>
1269 <input type=\"checkbox\" name=\"show-names-checkbox\" id=\"checkbox-2\" onchange=\"toggleNames()\">
1270 <label for=\"show-effects-checkbox\">effects</label>
1271 <input type=\"checkbox\" name=\"show-effects-checkbox\" id=\"checkbox-3\" onchange=\"toggleEffects()\">
1272 <label for=\"show-effects-checkbox\">duplicate forces</label>
1273 <input type=\"checkbox\" name=\"show-effects-checkbox\" id=\"checkbox-4\" onchange=\"toggleDupForces()\">
1274</fieldset>
1275"
1276}