Debuggaus
Yksi yksinkertaisimmista tavoista debugata Servoa on tulostaa kiinnostavia muuttujia println!-, eprintln!- tai dbg!-makroilla.
Yleensä niitä tulisi käyttää vain tilapäisesti; sinun täytyy poistaa ne tai muuntaa ne kunnolliseksi debug-lokituksesi ennen kuin pull request yhdistetään.
Debug-lokitus log-kirjastolla ja RUST_LOG-muuttujalla
Servo käyttää log-kirjastoa pitkäaikaiseen debug-lokitukseen ja virheviesteihin:
#![allow(unused)]
fn main() {
log::error!("hello");
log::warn!("hello");
log::info!("hello");
log::debug!("hello");
log::trace!("hello");
}
Toisin kuin println!-kaltaiset makrot, log lisää aikaleiman ja kertoo, mistä viesti tuli:
[2024-05-01T09:07:42Z ERROR servoshell::app] hello
[2024-05-01T09:07:42Z WARN servoshell::app] hello
[2024-05-01T09:07:42Z INFO servoshell::app] hello
[2024-05-01T09:07:42Z DEBUG servoshell::app] hello
[2024-05-01T09:07:42Z TRACE servoshell::app] hello
Voit suodattaa log-kirjaston tulostetta RUST_LOG-muuttujalla tason (off, error, warn, info, debug, trace) ja/tai viestin lähteen, eli niin sanotun „targetin”, mukaan.
Yleensä target on Rust-moduulin polku kuten servoshell::app, mutta on myös erityisiä targeteja (ks. § Tapahtumien jäljittäminen).
Aseta RUST_LOG lisäämällä se komennon eteen tai käyttämällä export-komentoa:
$ RUST_LOG=warn ./mach run -d test.html # Uses the prepended RUST_LOG.
$ export RUST_LOG=warn
$ ./mach run -d test.html # Uses the exported RUST_LOG.
Katso env_logger-dokumentaatiosta lisätietoja, mutta tässä muutamia esimerkkejä:
- ota käyttöön kaikki viestit
debug-tasolle asti, mutta eitrace-tasoa:RUST_LOG=debug - ota käyttöön kaikki viestit kohteista
servo::*,servoshell::*tai mistä tahansa targetista, joka alkaaservo:RUST_LOG=servo=trace(tai pelkkäRUST_LOG=servo) - ota käyttöön kaikki viestit kohteista, jotka alkavat
style, mutta vainerror- jawarn-viestit kohteestastyle::rule_tree:RUST_LOG=style,style::rule_tree=warn
Huomaa, että vaikka lokiviesti suodatetaan pois, se voi silti vaikuttaa suorituskykyyn, vaikkakin vain hieman.
Eräät käännökset Servosta, mukaan lukien viralliset yöjulkaisut, poistavat DEBUG- ja TRACE-viestit käännösaikana, joten niiden ottaminen käyttöön RUST_LOG-muuttujalla ei vaikuta mihinkään.
Tapahtumien jäljittäminen
Constellationissa, compositorissa ja servoshellissä lokataan muihin komponentteihin lähetetyt ja niistä vastaanotetut viestit targeteilla muodossa component>other@Event tai component<other@Event.
Tämä tarkoittaa, että voit valita ajonaikaisesti, mitä tapahtumatyyppejä lokataan RUST_LOG-muuttujalla!
Esimerkiksi constellationissa (lisätietoja):
- jäljitä vain scriptin tapahtumat:
RUST_LOG='constellation<=off,constellation<script@' - jäljitä kaikki tapahtumat paitsi ReadyToPresent-tapahtumat:
RUST_LOG='constellation<,constellation<compositor@ReadyToPresent=off' - jäljitä vain scriptin InitiateNavigateRequest-tapahtumat:
RUST_LOG='constellation<=off,constellation<script@InitiateNavigateRequest'
Compositorissa (lisätietoja):
- jäljitä vain MoveResizeWebView-tapahtumat:
RUST_LOG='compositor<constellation@MoveResizeWebView' - jäljitä kaikki tapahtumat paitsi Forwarded-tapahtumat:
RUST_LOG=compositor<,compositor<constellation@Forwarded=off
Servoshellissä (lisätietoja):
- jäljitä vain servon tapahtumat:
RUST_LOG='servoshell<=off,servoshell>=off,servoshell<servo@' - jäljitä kaikki tapahtumat paitsi AxisMotion-tapahtumat:
RUST_LOG='servoshell<,servoshell>,servoshell<winit@WindowEvent(AxisMotion)=off' - jäljitä vain winitin ikkunan siirto -tapahtumat:
RUST_LOG='servoshell<=off,servoshell>=off,servoshell<winit@WindowEvent(Moved)'
Tapahtumien jäljittäminen voi tuottaa valtavan määrän tulostetta. Yleensä suosittelemme seuraavaa konfiguraatiota, jotta tuloste pysyy käyttökelpoisena:
constellation<,constellation>,constellation<compositor@ForwardEvent(MouseMoveEvent)=off,constellation<compositor@LogEntry=off,constellation<compositor@ReadyToPresent=off,constellation<script@LogEntry=offcompositor<,compositor>servoshell<,servoshell>,servoshell<winit@DeviceEvent=off,servoshell<winit@MainEventsCleared=off,servoshell<winit@NewEvents(WaitCancelled)=off,servoshell<winit@RedrawEventsCleared=off,servoshell<winit@RedrawRequested=off,servoshell<winit@UserEvent(WakerEvent)=off,servoshell<winit@WindowEvent(CursorMoved)=off,servoshell<winit@WindowEvent(AxisMotion)=off
Muu debug-lokitus
mach run tekee tämän automaattisesti, mutta tulosta backtrace, kun Servo panikoi:
$ RUST_BACKTRACE=1 target/debug/servo test.html
Käytä -Z (-- --debug) ottaaksesi debug-asetukset käyttöön.
Esimerkiksi tulosta stacking context -puu jokaisen layoutin jälkeen tai hae apua näihin asetuksiin:
$ ./mach run -Z stacking-context-tree test.html
$ ./mach run -Z help # Lists available debug options.
$ ./mach run -- --debug help # Same as above: lists available debug options.
$ ./mach run --debug # Not the same! This just chooses target/debug.
Vaihtoehtoisesti voit käyttää SERVO_DIAGNOSTICS-ympäristömuuttujaa diagnostiikka-asetusten määrittämiseen.
$ SERVO_DIAGNOSTICS=style-tree ./mach run test.html
$ SERVO_DIAGNOSTICS=help ./mach run # Lists available debug options.
$ export SERVO_DIAGNOSTICS=style-tree,display-list
$ ./mach run test.html # Uses the exported SERVO_DIAGNOSTICS.
SERVO_DIAGNOSTICS-ympäristömuuttuja hyväksyy pilkuilla erotetut diagnostiikka-asetukset, samat kuin -Z-valinnan kautta saatavilla olevat.
Tämä ominaisuus on saatavilla vain debug- ja release-käännöksissä, ei production-käännöksissä.
macOS:llä voit myös lisätä Cocoa-spesifisiä debug-asetuksia ylimääräisen ---merkitsimen jälkeen:
$ ./mach run -- test.html -- -NSShowAllViews YES
Servoshellin ajaminen debuggerilla
Aja servoshell debuggerilla käyttämällä --debugger-cmd-valintaa.
Huomaa, että jos valitset gdb tai lldb, käytämme automaattisesti rust-gdb:tä ja rust-lldb:tä.
$ ./mach run --debugger-cmd=gdb test.html # Same as `--debugger-cmd=rust-gdb`.
$ ./mach run --debugger-cmd=lldb test.html # Same as `--debugger-cmd=rust-lldb`.
Välittääksesi debuggerille lisäasetuksia sinun täytyy ajaa debugger itse:
$ ./mach run --debugger-cmd=gdb -ex=r test.html # Passes `-ex=r` to servoshell.
$ rust-gdb -ex=r --args target/debug/servo test.html # Passes `-ex=r` to gdb.
$ ./mach run --debugger-cmd=lldb -o r test.html # Passes `-o r` to servoshell.
$ rust-lldb -o r -- target/debug/servo test.html # Passes `-o r` to lldb.
$ ./mach run --debugger-cmd=rr -M test.html # Passes `-M` to servoshell.
$ rr record -M target/debug/servo test.html # Passes `-M` to rr.
Monet debuggerit tarvitsevat lisäasetuksia erottamaan servoshellin argumentit omista valinnoistaan, ja --debugger-cmd välittää nämä asetukset automaattisesti muutamille debuggereille, mukaan lukien gdb ja lldb.
Muille debuggereille --debugger-cmd toimii vain, jos debugger ei tarvitse ylimääräisiä asetuksia:
$ ./mach run --debugger-cmd=rr test.html # Good, because it’s...
# servoshell arguments ^^^^^^^^^
$ rr target/debug/servo test.html # equivalent to this.
# servoshell arguments ^^^^^^^^^
$ ./mach run --debugger-cmd=renderdoccmd capture test.html # Bad, because it’s...
# renderdoccmd arguments? ^^^^^^^
# servoshell arguments ^^^^^^^^^
$ renderdoccmd target/debug/servo capture test.html # equivalent to this.
# => target/debug/servo is not a valid command.
$ renderdoccmd capture target/debug/servo test.html # Good.
# ^^^^^^^ renderdoccmd arguments
# servoshell arguments ^^^^^^^^^
Debuggaus gdb:llä tai lldb:llä
Etsi funktio nimen tai regexin perusteella:
(lldb) image lookup -r -n <name>
(gdb) info functions <name>
Listaa käynnissä olevat säikeet:
(lldb) thread list
(lldb) info threads
Muita gdb- tai lldb-komentoja:
(gdb) b a_servo_function # Add a breakpoint.
(gdb) run # Run until breakpoint is reached.
(gdb) bt # Print backtrace.
(gdb) frame n # Choose the stack frame by its number in `bt`.
(gdb) next # Run one line of code, stepping over function calls.
(gdb) step # Run one line of code, stepping into function calls.
(gdb) print varname # Print a variable in the current scope.
Katso tätä gdb-oppasta tai tätä lldb-oppasta lisätietoja varten.
Voit tarkastella muuttujia lldb:ssä myös kirjoittamalla gui ja käyttämällä nuolinäppäimiä muuttujien laajentamiseen:
(lldb) gui
┌──<Variables>───────────────────────────────────────────────────────────────────────────┐
│ ◆─(&mut gfx::paint_task::PaintTask<Box<CompositorProxy>>) self = 0x000070000163a5b0 │
│ ├─◆─(msg::constellation_msg::PipelineId) id │
│ ├─◆─(url::Url) _url │
│ │ ├─◆─(collections::string::String) scheme │
│ │ │ └─◆─(collections::vec::Vec<u8>) vec │
│ │ ├─◆─(url::SchemeData) scheme_data │
│ │ ├─◆─(core::option::Option<collections::string::String>) query │
│ │ └─◆─(core::option::Option<collections::string::String>) fragment │
│ ├─◆─(std::sync::mpsc::Receiver<gfx::paint_task::LayoutToPaintMsg>) layout_to_paint_port│
│ ├─◆─(std::sync::mpsc::Receiver<gfx::paint_task::ChromeToPaintMsg>) chrome_to_paint_port│
└────────────────────────────────────────────────────────────────────────────────────────┘
Jos lldb kaatuu tietyillä riveillä, joissa on profile()-funktio, et ole ainoa.
Kommentoi profilointikoodi pois ja pidä vain sisäinen funktio — sen pitäisi riittää.
Kääntävä debuggaus rr:llä (vain Linux)
rr on kuin gdb, mutta sen avulla voit kelata taaksepäin. Aloita ajamalla servoshell rr:n kautta:
$ ./mach run --debugger=rr test.html # Either this...
$ rr target/debug/servo test.html # ...or this.
Toista sitten jälki ja käytä gdb- tai rr-komentoja:
$ rr replay
(rr) continue
(rr) reverse-cont
Aja yksi tai useampi testi toistuvasti, kunnes tulos on odottamaton:
$ ./mach test-wpt --chaos path/to/test [path/to/test ...]
rr:n tallentamat jäljet voivat viedä paljon tilaa.
Poista ne hakemistosta ~/.local/share/rr.
OpenGL-debuggaus RenderDocilla (vain Linux tai Windows)
RenderDoc mahdollistaa Servon OpenGL-toiminnan debuggauksen. Aloita ajamalla servoshell renderdoccmd:n kautta:
$ renderdoccmd capture -d . target/debug/servo test.html
Kun servoshell on käynnissä, aja qrenderdoc ja valitse File > Attach to Running Instance.
Kun yhteys on muodostettu, voit painaa F12 tai Print Screen kaapataksesi ruudun.