Servo: Pretty print the flow tree

Created on 1 Aug 2016  Β·  49Comments  Β·  Source: servo/servo

When running ./mach run -Z dump-flow-tree, the output is not very human friendly:

β”‚  β”‚  β”‚  β”œβ”€ block(7fbf47f05310) sc=stackingcontextid(140459643095216) pos=logicalrect(h ltr, i100pxΓ—b100px, @ (i8px,b18.783333333333335px)),  floatspec-in=l 0px r 0px, floatspec-out=l 0px r 0px, overflow=overflow { scroll: rect(100pxΓ—100px at (0px,0px)), paint: rect(100pxΓ—100px at (0px,0px)) }
β”‚  β”‚  β”‚  β”‚  └─ ↑↑ fragment for block: specificfragmentinfo::generic(4) [] border_box=logicalrect(h ltr, i100pxΓ—b100px, @ (i0px,b0px)) damage=store_overflow
β”‚  β”‚  β”‚  β”œβ”€ flexflow { block_flow: block(7fbf47fe9310) sc=stackingcontextid(0) pos=logicalrect(h ltr, i10pxΓ—b100px, @ (i8px,b34.78333333333333px)),  floatspec-in=l 0px r 0px, ...

We can try to wrap the lines like

β”‚  β”‚  β”‚  β”œβ”€ block(7fbf47f05310) sc=stackingcontextid(140459643095216) 
β”‚  β”‚  β”‚  β”‚  β”‚                   pos=logicalrect(h ltr, i100pxΓ—b100px, @ (i8px,b18.783333333333335px)),  
β”‚  β”‚  β”‚  β”‚  β”‚                   floatspec-in=l 0px r 0px, 
β”‚  β”‚  β”‚  β”‚  β”‚                   floatspec-out=l 0px r 0px, 
β”‚  β”‚  β”‚  β”‚  β”‚                   overflow=overflow { scroll: rect(100pxΓ—100px at (0px,0px)), 
β”‚  β”‚  β”‚  β”‚  β”‚                   paint: rect(100pxΓ—100px at (0px,0px)) }
β”‚  β”‚  β”‚  β”‚  └─ ↑↑ fragment for block: specificfragmentinfo::generic(4) [] border_box=logicalrect(h ltr i100pxΓ—b100px, @ (i0px,b0px)) 
β”‚  β”‚  β”‚  β”‚                                                                damage=store_overflow

I'm not sure if we should hack the Debug::fmt trait or create a post-processor. The problem with Debug::fmt is that it's hard to keep the indentation level. But doing a post process will require us to keep the Debug::fmt and the post postprocessor format in sync.

C-assigned E-less easy

All 49 comments

Or maybe we should make Debug::fmt print a machine readable format, then we add some formatter in the mach to print it out in plain text. This would help if we want to create GUI debugging tools for layout in the future.

+1 for post-processor. Or maybe render it into some HTML-formatted page? so we can let browser to handle indentation etc.

@glennw Do you have any opinion on this? I heard that you are the last one who worked on this recently.

Here are some survey of existing layout debugging tools:

Gecko's ./mach run -layoutdebug
selection_030

Frame Tree Dump format:

...
                line 7f0626777020: count=1 state=block,clean,prevmarginclean,not impacted,not wrapped,before:leftbr+rightbr,after:nobr[0xa108] {900,182899,0,0} <
                  TableWrapper(_moz_generated_content_after)(-1)@7f0626776240 {900,182899,0,0} [state=0000000000000240] [content=7f061aee8a10] [sc=7f06267764e8:-moz-table-wrapper^7f0628044cc8^7f061aef6778^7f061aef5240]<
                    Table(_moz_generated_content_after)(-1)@7f06267762c0 {0,0,0,0} [state=0000100000000040] [content=7f061aee8a10] [sc=7f0628044cc8:after^7f061aef6778^7f061aef5240^7f0627b11e48]<
                      TableRowGroup(_moz_generated_content_after)(-1)@7f06267763d0 {0,0,0,0} [state=0000000000000040] [content=7f061aee8a10] [sc=7f061e0d36d8:-moz-table-row-group]<
                        TableRow(_moz_generated_content_after)(-1)@7f0626776450 {0,0,0,0} [state=0000000000000040] [content=7f061aee8a10] [sc=7f061e0a9690:-moz-table-row]<
                          TableCell(_moz_generated_content_after)(-1)@7f0626776590 {0,0,0,0} [state=0000000080000040] [content=7f061aee8a10] [sc=7f061d940368:-moz-table-cell]<
                            Block(_moz_generated_content_after)(-1)@7f0626776940 {0,0,0,0} [state=0000000000d00040] [content=7f061aee8a10] [sc=7f0628068728:-moz-cell-content]<
                              line 7f0626776a48: count=1 state=inline,clean,prevmarginclean,not impacted,not wrapped,before:nobr,after:nobr[0x300] {0,0,0,0} <
                                Text(0)" "@7f06267769d8 {0,0,0,0} [state=4000000028600040] [content=7f061aee8aa0] [sc=7f06240eda20:-moz-text^7f0628044cc8^7f061aef6778^7f061aef5240] [run=7f061bf88d00][0,1,T] 
                              >
                            >
                          >
                        >
                      >
                    >
                    ColGroupList 7f0626776398 <
                      TableColGroup(_moz_generated_content_after)(-1)@7f0626776b48 {0,0,0,0} [state=0000000080000040] [content=7f061aee8a10] [sc=7f06280b7e00:-moz-table-column-group]<
                        TableCol(_moz_generated_content_after)(-1)@7f0626776c70 {0,0,0,0} [state=0000000030000040] [content=7f061aee8a10] [sc=7f061e0a9bf8:-moz-table-column]
                      >
                    >
                  >
                >
              >
            >
          >
        >
      >
    >
  >
>

WebKit has a specialized test client called DumpRenderTree, which is like a headless browser which dumps the render tree for layout testing.

The output looks like this:

Content-Type: text/plain
layer at (0,0) size 808x820
  RenderView at (0,0) size 800x600
layer at (0,0) size 800x820
  RenderBlock {HTML} at (0,0) size 800x820
    RenderBody {BODY} at (8,8) size 784x804
      RenderHTMLCanvas {CANVAS} at (0,0) size 800x800 [bgcolor=#808080]
      RenderText {#text} at (0,0) size 0x0
#EOF
#EOF

Ref: https://trac.webkit.org/wiki/Writing%20Layout%20Tests%20for%20DumpRenderTree#

Both tools dumps the tree in plain text, which is console-friendly but not optimal for human reader or other tools to parse. I'll make it emit a JSON object and write a python (?) formatter and/or visualization tool.

I'd also want to create a debug tool that dumps the flow tree in every key stage in the layout process, and we can have a time slider to explore how the flow tree evolves during the layout process

Thanks for taking this on, and a huge :+1: for dumping at key stages so that we can have a time slider to show how the flow tree evolves during layout. Visualizations always aid understanding, and layout is a somewhat opaque process to many developers.

I also agree that having JSON (or some other format that is SUPER easily parsed by off the shelf libraries) is a great strategy.

I'm also considering YAML. YAML is more human readable, so before we build any fancy tool, developers can still look at the raw output and benefit from the improved readability

@nox points out that we can use rustc_serialize

I would probably keep the old Debug::fmt() and change the Flow::print() (i.e. the flow tree dump function) to use the json serialize function instead of Debug:fmt().

And as @nox said it would be even better to switch to serde_json from rustc_serialize

This looks exactly what we want: https://github.com/servo/servo/commit/acedb166707aa2e8fd02e6c7d943147394c34609

But there is a bug in it so it always print an empty trace. I'll submit a patch for that right away.

They way to use it is ./mach run -d -Z trace-layout https://servo.org, and a layout_trace.json file will be created. We need to document this somewhere.

@glennw , you mentioned some external tool for layout debugging in https://github.com/servo/servo/commit/acedb166707aa2e8fd02e6c7d943147394c34609, may I ask where can I find the tool?

I found it, but looks like it was removed: https://github.com/servo/servo/pull/3350

Removed by:

commit e7510ab90c3482233ca8b188d748216901041970
Author: Matt Brubeck <[email protected]>
Date:   Tue May 24 17:55:01 2016 -0700

    Remove the layout trace viewer

    It's unmaintained and hasn't worked for years, I think.

Previous attempt and discussion: #13092

Now I use -Z trace-layout (with /etc/layout_viewer/) most of the time, because it snapshot the flow tree at every layout step, so you can see how the flow tree evolves. But if someone still need the -Z dump-flow-tree in json, they can consider using the serde_json infrastructure I created. I'm willing to mentor.

Hi! I am a very noobie to Servo, but may I work on it with some help? (:

@Ilphrin That should be fine! Take a look at the previous discussion and attempt and ask questions about anything that's unclear!

Hi @jdm ! Well, I don't really know where to start ^^" I have built servo, and tried the basic example with -Z dump-flow-tree.

Hi @Ilphrin !

So first, you can found how the dump-flow-tree works here. Then you'll need to change that to use serde_json's to_value() and to_string() to format that as we did for trace-layout. Once you done that, you should be able to dump a JOSN string of the flow tree into the log. (You can probably open a pull request then)

The next thing you can do is to write a little python script or Rust script to parse the JSON string, format it in a pretty way (see the first comment). That would be the second pull request.

Let me know if you are stuck on anything. Happy hacking :)

Hi @shinglyu! Thanks a lot for your clarifications. I've looked around the two links you gave me and, if I don't misunderstand, I need to change the content of the print function of the FlowRef type to use serde_json. The problem is I didn't find anything on the Servo doc about this print function for this type, and where it resides...

The documentation for serde_json lives at http://doc.servo.org/serde_json/index.html, and there's to_value and to_string methods.

@Ilphrin Are you still working on this? If not, @jdhorwitz would you be interested in tackling this instead?

Sorry I am terribly busy with school :/ I could work on it but in about a month, so if someone else is interested in doing this it's ok I'll take an other bug later ;)

Hey! It seems as if you need somebody to do this. I would really like to give it a try, otherwise I would have to do something else this weekend. Oh, and don't be suprised. I really just had no idea what to use github for until now, so my profile is quite empty.

I would give @jdhorwitz the right of refusal here.

For how long?

It seems like he is unresponsive, you can go ahead and work on this!

Okay, I have a question. At the moment, the fmt::Debug trait for BaseFlow uses more data than Serde::ser::Serialize. Considering Debug, should I make Serialize use the remaining fields? It would change the output of trace-layout I guess.

@vernans I think simply add more fields is fine. Just be careful not to alter the structure of the JSON output (e.g. more or fewer layers of parenthesis)

@vernans Have you made any progress here?

Unassigning due to lack of response.

@KiChjang @jdm can i work on it ?

Please do!

@shinglyu, i saw the flow of dump-flow-tree, so I've to make the all flow class(inheriting flow trait) serializable and then do serde_json::to_string(root_flow) ?

Hi @shinglyu , got the basic json running with help from @vernans code from his repo.

Can you please tell me which field from basic flow should I add ?

@shinglyu please review the changes made in this tree: https://github.com/murarisumit/servo/tree/12675

@murarisumit Sorry for the delay, the code looks fine to me (https://github.com/servo/servo/compare/master...murarisumit:12675)

Would you mind posting an example of the json output? Just want to make sure it's valid json and easily parsable.

@shinglyu It's slightly large file, so sharing it via gist:

https://gist.github.com/murarisumit/63667a8376fe74099bb9bb5faedc369b

@shinglyu Did you look at the json output? Is this ready for a PR?

@murarisumit The JSON output looks nice. Feel free to open a PR.

cc @mihajlija, who was looking into something like this.

hi @shinglyu, there are many changes since my last commit. My forked repo is around 3000 commit behind the master, and there are changes in master repo that I'm not aware of it.

I've merge it with the current master repo, let me know what next should I do next with it ?

@murarisumit So are you having trouble rebasing (taking in the master changes) or creating a PR?
If you are having trouble rebasing, check out my blog post.

Otherwise, push your code to your fork and go to servo/servo's Pull requests page, there is a button to create a pull request. We can then continue to review and test your code in the pull request page.

Was this done, in the end?

Never mind… #18266.

Latest attempt was at #18266, with a review comment that needs to be addressed.

I am going to do this

@highfive: assign me

Hey @tigercosmos! Thanks for your interest in working on this issue. It's now assigned to you!

Was this page helpful?
0 / 5 - 0 ratings