123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115 |
- .. SPDX-License-Identifier: GPL-2.0
- ======================
- Histogram Design Notes
- ======================
- :Author: Tom Zanussi <[email protected]>
- This document attempts to provide a description of how the ftrace
- histograms work and how the individual pieces map to the data
- structures used to implement them in trace_events_hist.c and
- tracing_map.c.
- Note: All the ftrace histogram command examples assume the working
- directory is the ftrace /tracing directory. For example::
- # cd /sys/kernel/debug/tracing
- Also, the histogram output displayed for those commands will be
- generally be truncated - only enough to make the point is displayed.
- 'hist_debug' trace event files
- ==============================
- If the kernel is compiled with CONFIG_HIST_TRIGGERS_DEBUG set, an
- event file named 'hist_debug' will appear in each event's
- subdirectory. This file can be read at any time and will display some
- of the hist trigger internals described in this document. Specific
- examples and output will be described in test cases below.
- Basic histograms
- ================
- First, basic histograms. Below is pretty much the simplest thing you
- can do with histograms - create one with a single key on a single
- event and cat the output::
- # echo 'hist:keys=pid' >> events/sched/sched_waking/trigger
- # cat events/sched/sched_waking/hist
- { pid: 18249 } hitcount: 1
- { pid: 13399 } hitcount: 1
- { pid: 17973 } hitcount: 1
- { pid: 12572 } hitcount: 1
- ...
- { pid: 10 } hitcount: 921
- { pid: 18255 } hitcount: 1444
- { pid: 25526 } hitcount: 2055
- { pid: 5257 } hitcount: 2055
- { pid: 27367 } hitcount: 2055
- { pid: 1728 } hitcount: 2161
- Totals:
- Hits: 21305
- Entries: 183
- Dropped: 0
- What this does is create a histogram on the sched_waking event using
- pid as a key and with a single value, hitcount, which even if not
- explicitly specified, exists for every histogram regardless.
- The hitcount value is a per-bucket value that's automatically
- incremented on every hit for the given key, which in this case is the
- pid.
- So in this histogram, there's a separate bucket for each pid, and each
- bucket contains a value for that bucket, counting the number of times
- sched_waking was called for that pid.
- Each histogram is represented by a hist_data struct.
- To keep track of each key and value field in the histogram, hist_data
- keeps an array of these fields named fields[]. The fields[] array is
- an array containing struct hist_field representations of each
- histogram val and key in the histogram (variables are also included
- here, but are discussed later). So for the above histogram we have one
- key and one value; in this case the one value is the hitcount value,
- which all histograms have, regardless of whether they define that
- value or not, which the above histogram does not.
- Each struct hist_field contains a pointer to the ftrace_event_field
- from the event's trace_event_file along with various bits related to
- that such as the size, offset, type, and a hist_field_fn_t function,
- which is used to grab the field's data from the ftrace event buffer
- (in most cases - some hist_fields such as hitcount don't directly map
- to an event field in the trace buffer - in these cases the function
- implementation gets its value from somewhere else). The flags field
- indicates which type of field it is - key, value, variable, variable
- reference, etc., with value being the default.
- The other important hist_data data structure in addition to the
- fields[] array is the tracing_map instance created for the histogram,
- which is held in the .map member. The tracing_map implements the
- lock-free hash table used to implement histograms (see
- kernel/trace/tracing_map.h for much more discussion about the
- low-level data structures implementing the tracing_map). For the
- purposes of this discussion, the tracing_map contains a number of
- buckets, each bucket corresponding to a particular tracing_map_elt
- object hashed by a given histogram key.
- Below is a diagram the first part of which describes the hist_data and
- associated key and value fields for the histogram described above. As
- you can see, there are two fields in the fields array, one val field
- for the hitcount and one key field for the pid key.
- Below that is a diagram of a run-time snapshot of what the tracing_map
- might look like for a given run. It attempts to show the
- relationships between the hist_data fields and the tracing_map
- elements for a couple hypothetical keys and values.::
- +------------------+
- | hist_data |
- +------------------+ +----------------+
- | .fields[] |---->| val = hitcount |----------------------------+
- +----------------+ +----------------+ |
- | .map | | .size | |
- +----------------+ +--------------+ |
- | .offset | |
- +--------------+ |
- | .fn() | |
- +--------------+ |
- . |
- . |
- . |
- +----------------+ <--- n_vals |
- | key = pid |----------------------------|--+
- +----------------+ | |
- | .size | | |
- +--------------+ | |
- | .offset | | |
- +--------------+ | |
- | .fn() | | |
- +----------------+ <--- n_fields | |
- | unused | | |
- +----------------+ | |
- | | | |
- +--------------+ | |
- | | | |
- +--------------+ | |
- | | | |
- +--------------+ | |
- n_keys = n_fields - n_vals | |
- The hist_data n_vals and n_fields delineate the extent of the fields[] | |
- array and separate keys from values for the rest of the code. | |
- Below is a run-time representation of the tracing_map part of the | |
- histogram, with pointers from various parts of the fields[] array | |
- to corresponding parts of the tracing_map. | |
- The tracing_map consists of an array of tracing_map_entrys and a set | |
- of preallocated tracing_map_elts (abbreviated below as map_entry and | |
- map_elt). The total number of map_entrys in the hist_data.map array = | |
- map->max_elts (actually map->map_size but only max_elts of those are | |
- used. This is a property required by the map_insert() algorithm). | |
- If a map_entry is unused, meaning no key has yet hashed into it, its | |
- .key value is 0 and its .val pointer is NULL. Once a map_entry has | |
- been claimed, the .key value contains the key's hash value and the | |
- .val member points to a map_elt containing the full key and an entry | |
- for each key or value in the map_elt.fields[] array. There is an | |
- entry in the map_elt.fields[] array corresponding to each hist_field | |
- in the histogram, and this is where the continually aggregated sums | |
- corresponding to each histogram value are kept. | |
- The diagram attempts to show the relationship between the | |
- hist_data.fields[] and the map_elt.fields[] with the links drawn | |
- between diagrams::
- +-----------+ | |
- | hist_data | | |
- +-----------+ | |
- | .fields | | |
- +---------+ +-----------+ | |
- | .map |---->| map_entry | | |
- +---------+ +-----------+ | |
- | .key |---> 0 | |
- +---------+ | |
- | .val |---> NULL | |
- +-----------+ | |
- | map_entry | | |
- +-----------+ | |
- | .key |---> pid = 999 | |
- +---------+ +-----------+ | |
- | .val |--->| map_elt | | |
- +---------+ +-----------+ | |
- . | .key |---> full key * | |
- . +---------+ +---------------+ | |
- . | .fields |--->| .sum (val) |<-+ |
- +-----------+ +---------+ | 2345 | | |
- | map_entry | +---------------+ | |
- +-----------+ | .offset (key) |<----+
- | .key |---> 0 | 0 | | |
- +---------+ +---------------+ | |
- | .val |---> NULL . | |
- +-----------+ . | |
- | map_entry | . | |
- +-----------+ +---------------+ | |
- | .key | | .sum (val) or | | |
- +---------+ +---------+ | .offset (key) | | |
- | .val |--->| map_elt | +---------------+ | |
- +-----------+ +---------+ | .sum (val) or | | |
- | map_entry | | .offset (key) | | |
- +-----------+ +---------------+ | |
- | .key |---> pid = 4444 | |
- +---------+ +-----------+ | |
- | .val | | map_elt | | |
- +---------+ +-----------+ | |
- | .key |---> full key * | |
- +---------+ +---------------+ | |
- | .fields |--->| .sum (val) |<-+ |
- +---------+ | 65523 | |
- +---------------+ |
- | .offset (key) |<----+
- | 0 |
- +---------------+
- .
- .
- .
- +---------------+
- | .sum (val) or |
- | .offset (key) |
- +---------------+
- | .sum (val) or |
- | .offset (key) |
- +---------------+
- Abbreviations used in the diagrams::
- hist_data = struct hist_trigger_data
- hist_data.fields = struct hist_field
- fn = hist_field_fn_t
- map_entry = struct tracing_map_entry
- map_elt = struct tracing_map_elt
- map_elt.fields = struct tracing_map_field
- Whenever a new event occurs and it has a hist trigger associated with
- it, event_hist_trigger() is called. event_hist_trigger() first deals
- with the key: for each subkey in the key (in the above example, there
- is just one subkey corresponding to pid), the hist_field that
- represents that subkey is retrieved from hist_data.fields[] and the
- hist_field_fn_t fn() associated with that field, along with the
- field's size and offset, is used to grab that subkey's data from the
- current trace record.
- Once the complete key has been retrieved, it's used to look that key
- up in the tracing_map. If there's no tracing_map_elt associated with
- that key, an empty one is claimed and inserted in the map for the new
- key. In either case, the tracing_map_elt associated with that key is
- returned.
- Once a tracing_map_elt available, hist_trigger_elt_update() is called.
- As the name implies, this updates the element, which basically means
- updating the element's fields. There's a tracing_map_field associated
- with each key and value in the histogram, and each of these correspond
- to the key and value hist_fields created when the histogram was
- created. hist_trigger_elt_update() goes through each value hist_field
- and, as for the keys, uses the hist_field's fn() and size and offset
- to grab the field's value from the current trace record. Once it has
- that value, it simply adds that value to that field's
- continually-updated tracing_map_field.sum member. Some hist_field
- fn()s, such as for the hitcount, don't actually grab anything from the
- trace record (the hitcount fn() just increments the counter sum by 1),
- but the idea is the same.
- Once all the values have been updated, hist_trigger_elt_update() is
- done and returns. Note that there are also tracing_map_fields for
- each subkey in the key, but hist_trigger_elt_update() doesn't look at
- them or update anything - those exist only for sorting, which can
- happen later.
- Basic histogram test
- --------------------
- This is a good example to try. It produces 3 value fields and 2 key
- fields in the output::
- # echo 'hist:keys=common_pid,call_site.sym:values=bytes_req,bytes_alloc,hitcount' >> events/kmem/kmalloc/trigger
- To see the debug data, cat the kmem/kmalloc's 'hist_debug' file. It
- will show the trigger info of the histogram it corresponds to, along
- with the address of the hist_data associated with the histogram, which
- will become useful in later examples. It then displays the number of
- total hist_fields associated with the histogram along with a count of
- how many of those correspond to keys and how many correspond to values.
- It then goes on to display details for each field, including the
- field's flags and the position of each field in the hist_data's
- fields[] array, which is useful information for verifying that things
- internally appear correct or not, and which again will become even
- more useful in further examples::
- # cat events/kmem/kmalloc/hist_debug
- # event histogram
- #
- # trigger info: hist:keys=common_pid,call_site.sym:vals=hitcount,bytes_req,bytes_alloc:sort=hitcount:size=2048 [active]
- #
- hist_data: 000000005e48c9a5
- n_vals: 3
- n_keys: 2
- n_fields: 5
- val fields:
- hist_data->fields[0]:
- flags:
- VAL: HIST_FIELD_FL_HITCOUNT
- type: u64
- size: 8
- is_signed: 0
- hist_data->fields[1]:
- flags:
- VAL: normal u64 value
- ftrace_event_field name: bytes_req
- type: size_t
- size: 8
- is_signed: 0
- hist_data->fields[2]:
- flags:
- VAL: normal u64 value
- ftrace_event_field name: bytes_alloc
- type: size_t
- size: 8
- is_signed: 0
- key fields:
- hist_data->fields[3]:
- flags:
- HIST_FIELD_FL_KEY
- ftrace_event_field name: common_pid
- type: int
- size: 8
- is_signed: 1
- hist_data->fields[4]:
- flags:
- HIST_FIELD_FL_KEY
- ftrace_event_field name: call_site
- type: unsigned long
- size: 8
- is_signed: 0
- The commands below can be used to clean things up for the next test::
- # echo '!hist:keys=common_pid,call_site.sym:values=bytes_req,bytes_alloc,hitcount' >> events/kmem/kmalloc/trigger
- Variables
- =========
- Variables allow data from one hist trigger to be saved by one hist
- trigger and retrieved by another hist trigger. For example, a trigger
- on the sched_waking event can capture a timestamp for a particular
- pid, and later a sched_switch event that switches to that pid event
- can grab the timestamp and use it to calculate a time delta between
- the two events::
- # echo 'hist:keys=pid:ts0=common_timestamp.usecs' >>
- events/sched/sched_waking/trigger
- # echo 'hist:keys=next_pid:wakeup_lat=common_timestamp.usecs-$ts0' >>
- events/sched/sched_switch/trigger
- In terms of the histogram data structures, variables are implemented
- as another type of hist_field and for a given hist trigger are added
- to the hist_data.fields[] array just after all the val fields. To
- distinguish them from the existing key and val fields, they're given a
- new flag type, HIST_FIELD_FL_VAR (abbreviated FL_VAR) and they also
- make use of a new .var.idx field member in struct hist_field, which
- maps them to an index in a new map_elt.vars[] array added to the
- map_elt specifically designed to store and retrieve variable values.
- The diagram below shows those new elements and adds a new variable
- entry, ts0, corresponding to the ts0 variable in the sched_waking
- trigger above.
- sched_waking histogram
- ----------------------::
- +------------------+
- | hist_data |<-------------------------------------------------------+
- +------------------+ +-------------------+ |
- | .fields[] |-->| val = hitcount | |
- +----------------+ +-------------------+ |
- | .map | | .size | |
- +----------------+ +-----------------+ |
- | .offset | |
- +-----------------+ |
- | .fn() | |
- +-----------------+ |
- | .flags | |
- +-----------------+ |
- | .var.idx | |
- +-------------------+ |
- | var = ts0 | |
- +-------------------+ |
- | .size | |
- +-----------------+ |
- | .offset | |
- +-----------------+ |
- | .fn() | |
- +-----------------+ |
- | .flags & FL_VAR | |
- +-----------------+ |
- | .var.idx |----------------------------+-+ |
- +-----------------+ | | |
- . | | |
- . | | |
- . | | |
- +-------------------+ <--- n_vals | | |
- | key = pid | | | |
- +-------------------+ | | |
- | .size | | | |
- +-----------------+ | | |
- | .offset | | | |
- +-----------------+ | | |
- | .fn() | | | |
- +-----------------+ | | |
- | .flags & FL_KEY | | | |
- +-----------------+ | | |
- | .var.idx | | | |
- +-------------------+ <--- n_fields | | |
- | unused | | | |
- +-------------------+ | | |
- | | | | |
- +-----------------+ | | |
- | | | | |
- +-----------------+ | | |
- | | | | |
- +-----------------+ | | |
- | | | | |
- +-----------------+ | | |
- | | | | |
- +-----------------+ | | |
- n_keys = n_fields - n_vals | | |
- | | |
- This is very similar to the basic case. In the above diagram, we can | | |
- see a new .flags member has been added to the struct hist_field | | |
- struct, and a new entry added to hist_data.fields representing the ts0 | | |
- variable. For a normal val hist_field, .flags is just 0 (modulo | | |
- modifier flags), but if the value is defined as a variable, the .flags | | |
- contains a set FL_VAR bit. | | |
- As you can see, the ts0 entry's .var.idx member contains the index | | |
- into the tracing_map_elts' .vars[] array containing variable values. | | |
- This idx is used whenever the value of the variable is set or read. | | |
- The map_elt.vars idx assigned to the given variable is assigned and | | |
- saved in .var.idx by create_tracing_map_fields() after it calls | | |
- tracing_map_add_var(). | | |
- Below is a representation of the histogram at run-time, which | | |
- populates the map, along with correspondence to the above hist_data and | | |
- hist_field data structures. | | |
- The diagram attempts to show the relationship between the | | |
- hist_data.fields[] and the map_elt.fields[] and map_elt.vars[] with | | |
- the links drawn between diagrams. For each of the map_elts, you can | | |
- see that the .fields[] members point to the .sum or .offset of a key | | |
- or val and the .vars[] members point to the value of a variable. The | | |
- arrows between the two diagrams show the linkages between those | | |
- tracing_map members and the field definitions in the corresponding | | |
- hist_data fields[] members.::
- +-----------+ | | |
- | hist_data | | | |
- +-----------+ | | |
- | .fields | | | |
- +---------+ +-----------+ | | |
- | .map |---->| map_entry | | | |
- +---------+ +-----------+ | | |
- | .key |---> 0 | | |
- +---------+ | | |
- | .val |---> NULL | | |
- +-----------+ | | |
- | map_entry | | | |
- +-----------+ | | |
- | .key |---> pid = 999 | | |
- +---------+ +-----------+ | | |
- | .val |--->| map_elt | | | |
- +---------+ +-----------+ | | |
- . | .key |---> full key * | | |
- . +---------+ +---------------+ | | |
- . | .fields |--->| .sum (val) | | | |
- . +---------+ | 2345 | | | |
- . +--| .vars | +---------------+ | | |
- . | +---------+ | .offset (key) | | | |
- . | | 0 | | | |
- . | +---------------+ | | |
- . | . | | |
- . | . | | |
- . | . | | |
- . | +---------------+ | | |
- . | | .sum (val) or | | | |
- . | | .offset (key) | | | |
- . | +---------------+ | | |
- . | | .sum (val) or | | | |
- . | | .offset (key) | | | |
- . | +---------------+ | | |
- . | | | |
- . +---------------->+---------------+ | | |
- . | ts0 |<--+ | |
- . | 113345679876 | | | |
- . +---------------+ | | |
- . | unused | | | |
- . | | | | |
- . +---------------+ | | |
- . . | | |
- . . | | |
- . . | | |
- . +---------------+ | | |
- . | unused | | | |
- . | | | | |
- . +---------------+ | | |
- . | unused | | | |
- . | | | | |
- . +---------------+ | | |
- . | | |
- +-----------+ | | |
- | map_entry | | | |
- +-----------+ | | |
- | .key |---> pid = 4444 | | |
- +---------+ +-----------+ | | |
- | .val |--->| map_elt | | | |
- +---------+ +-----------+ | | |
- . | .key |---> full key * | | |
- . +---------+ +---------------+ | | |
- . | .fields |--->| .sum (val) | | | |
- +---------+ | 2345 | | | |
- +--| .vars | +---------------+ | | |
- | +---------+ | .offset (key) | | | |
- | | 0 | | | |
- | +---------------+ | | |
- | . | | |
- | . | | |
- | . | | |
- | +---------------+ | | |
- | | .sum (val) or | | | |
- | | .offset (key) | | | |
- | +---------------+ | | |
- | | .sum (val) or | | | |
- | | .offset (key) | | | |
- | +---------------+ | | |
- | | | |
- | +---------------+ | | |
- +---------------->| ts0 |<--+ | |
- | 213499240729 | | |
- +---------------+ | |
- | unused | | |
- | | | |
- +---------------+ | |
- . | |
- . | |
- . | |
- +---------------+ | |
- | unused | | |
- | | | |
- +---------------+ | |
- | unused | | |
- | | | |
- +---------------+ | |
- For each used map entry, there's a map_elt pointing to an array of | |
- .vars containing the current value of the variables associated with | |
- that histogram entry. So in the above, the timestamp associated with | |
- pid 999 is 113345679876, and the timestamp variable in the same | |
- .var.idx for pid 4444 is 213499240729. | |
- sched_switch histogram | |
- ---------------------- | |
- The sched_switch histogram paired with the above sched_waking | |
- histogram is shown below. The most important aspect of the | |
- sched_switch histogram is that it references a variable on the | |
- sched_waking histogram above. | |
- The histogram diagram is very similar to the others so far displayed, | |
- but it adds variable references. You can see the normal hitcount and | |
- key fields along with a new wakeup_lat variable implemented in the | |
- same way as the sched_waking ts0 variable, but in addition there's an | |
- entry with the new FL_VAR_REF (short for HIST_FIELD_FL_VAR_REF) flag. | |
- Associated with the new var ref field are a couple of new hist_field | |
- members, var.hist_data and var_ref_idx. For a variable reference, the | |
- var.hist_data goes with the var.idx, which together uniquely identify | |
- a particular variable on a particular histogram. The var_ref_idx is | |
- just the index into the var_ref_vals[] array that caches the values of | |
- each variable whenever a hist trigger is updated. Those resulting | |
- values are then finally accessed by other code such as trace action | |
- code that uses the var_ref_idx values to assign param values. | |
- The diagram below describes the situation for the sched_switch | |
- histogram referred to before::
- # echo 'hist:keys=next_pid:wakeup_lat=common_timestamp.usecs-$ts0' >> | |
- events/sched/sched_switch/trigger | |
- | |
- +------------------+ | |
- | hist_data | | |
- +------------------+ +-----------------------+ | |
- | .fields[] |-->| val = hitcount | | |
- +----------------+ +-----------------------+ | |
- | .map | | .size | | |
- +----------------+ +---------------------+ | |
- +--| .var_refs[] | | .offset | | |
- | +----------------+ +---------------------+ | |
- | | .fn() | | |
- | var_ref_vals[] +---------------------+ | |
- | +-------------+ | .flags | | |
- | | $ts0 |<---+ +---------------------+ | |
- | +-------------+ | | .var.idx | | |
- | | | | +---------------------+ | |
- | +-------------+ | | .var.hist_data | | |
- | | | | +---------------------+ | |
- | +-------------+ | | .var_ref_idx | | |
- | | | | +-----------------------+ | |
- | +-------------+ | | var = wakeup_lat | | |
- | . | +-----------------------+ | |
- | . | | .size | | |
- | . | +---------------------+ | |
- | +-------------+ | | .offset | | |
- | | | | +---------------------+ | |
- | +-------------+ | | .fn() | | |
- | | | | +---------------------+ | |
- | +-------------+ | | .flags & FL_VAR | | |
- | | +---------------------+ | |
- | | | .var.idx | | |
- | | +---------------------+ | |
- | | | .var.hist_data | | |
- | | +---------------------+ | |
- | | | .var_ref_idx | | |
- | | +---------------------+ | |
- | | . | |
- | | . | |
- | | . | |
- | | +-----------------------+ <--- n_vals | |
- | | | key = pid | | |
- | | +-----------------------+ | |
- | | | .size | | |
- | | +---------------------+ | |
- | | | .offset | | |
- | | +---------------------+ | |
- | | | .fn() | | |
- | | +---------------------+ | |
- | | | .flags | | |
- | | +---------------------+ | |
- | | | .var.idx | | |
- | | +-----------------------+ <--- n_fields | |
- | | | unused | | |
- | | +-----------------------+ | |
- | | | | | |
- | | +---------------------+ | |
- | | | | | |
- | | +---------------------+ | |
- | | | | | |
- | | +---------------------+ | |
- | | | | | |
- | | +---------------------+ | |
- | | | | | |
- | | +---------------------+ | |
- | | n_keys = n_fields - n_vals | |
- | | | |
- | | | |
- | | +-----------------------+ | |
- +---------------------->| var_ref = $ts0 | | |
- | +-----------------------+ | |
- | | .size | | |
- | +---------------------+ | |
- | | .offset | | |
- | +---------------------+ | |
- | | .fn() | | |
- | +---------------------+ | |
- | | .flags & FL_VAR_REF | | |
- | +---------------------+ | |
- | | .var.idx |--------------------------+ |
- | +---------------------+ |
- | | .var.hist_data |----------------------------+
- | +---------------------+
- +---| .var_ref_idx |
- +---------------------+
- Abbreviations used in the diagrams::
- hist_data = struct hist_trigger_data
- hist_data.fields = struct hist_field
- fn = hist_field_fn_t
- FL_KEY = HIST_FIELD_FL_KEY
- FL_VAR = HIST_FIELD_FL_VAR
- FL_VAR_REF = HIST_FIELD_FL_VAR_REF
- When a hist trigger makes use of a variable, a new hist_field is
- created with flag HIST_FIELD_FL_VAR_REF. For a VAR_REF field, the
- var.idx and var.hist_data take the same values as the referenced
- variable, as well as the referenced variable's size, type, and
- is_signed values. The VAR_REF field's .name is set to the name of the
- variable it references. If a variable reference was created using the
- explicit system.event.$var_ref notation, the hist_field's system and
- event_name variables are also set.
- So, in order to handle an event for the sched_switch histogram,
- because we have a reference to a variable on another histogram, we
- need to resolve all variable references first. This is done via the
- resolve_var_refs() calls made from event_hist_trigger(). What this
- does is grabs the var_refs[] array from the hist_data representing the
- sched_switch histogram. For each one of those, the referenced
- variable's var.hist_data along with the current key is used to look up
- the corresponding tracing_map_elt in that histogram. Once found, the
- referenced variable's var.idx is used to look up the variable's value
- using tracing_map_read_var(elt, var.idx), which yields the value of
- the variable for that element, ts0 in the case above. Note that both
- the hist_fields representing both the variable and the variable
- reference have the same var.idx, so this is straightforward.
- Variable and variable reference test
- ------------------------------------
- This example creates a variable on the sched_waking event, ts0, and
- uses it in the sched_switch trigger. The sched_switch trigger also
- creates its own variable, wakeup_lat, but nothing yet uses it::
- # echo 'hist:keys=pid:ts0=common_timestamp.usecs' >> events/sched/sched_waking/trigger
- # echo 'hist:keys=next_pid:wakeup_lat=common_timestamp.usecs-$ts0' >> events/sched/sched_switch/trigger
- Looking at the sched_waking 'hist_debug' output, in addition to the
- normal key and value hist_fields, in the val fields section we see a
- field with the HIST_FIELD_FL_VAR flag, which indicates that that field
- represents a variable. Note that in addition to the variable name,
- contained in the var.name field, it includes the var.idx, which is the
- index into the tracing_map_elt.vars[] array of the actual variable
- location. Note also that the output shows that variables live in the
- same part of the hist_data->fields[] array as normal values::
- # cat events/sched/sched_waking/hist_debug
- # event histogram
- #
- # trigger info: hist:keys=pid:vals=hitcount:ts0=common_timestamp.usecs:sort=hitcount:size=2048:clock=global [active]
- #
- hist_data: 000000009536f554
- n_vals: 2
- n_keys: 1
- n_fields: 3
- val fields:
- hist_data->fields[0]:
- flags:
- VAL: HIST_FIELD_FL_HITCOUNT
- type: u64
- size: 8
- is_signed: 0
- hist_data->fields[1]:
- flags:
- HIST_FIELD_FL_VAR
- var.name: ts0
- var.idx (into tracing_map_elt.vars[]): 0
- type: u64
- size: 8
- is_signed: 0
- key fields:
- hist_data->fields[2]:
- flags:
- HIST_FIELD_FL_KEY
- ftrace_event_field name: pid
- type: pid_t
- size: 8
- is_signed: 1
- Moving on to the sched_switch trigger hist_debug output, in addition
- to the unused wakeup_lat variable, we see a new section displaying
- variable references. Variable references are displayed in a separate
- section because in addition to being logically separate from
- variables and values, they actually live in a separate hist_data
- array, var_refs[].
- In this example, the sched_switch trigger has a reference to a
- variable on the sched_waking trigger, $ts0. Looking at the details,
- we can see that the var.hist_data value of the referenced variable
- matches the previously displayed sched_waking trigger, and the var.idx
- value matches the previously displayed var.idx value for that
- variable. Also displayed is the var_ref_idx value for that variable
- reference, which is where the value for that variable is cached for
- use when the trigger is invoked::
- # cat events/sched/sched_switch/hist_debug
- # event histogram
- #
- # trigger info: hist:keys=next_pid:vals=hitcount:wakeup_lat=common_timestamp.usecs-$ts0:sort=hitcount:size=2048:clock=global [active]
- #
- hist_data: 00000000f4ee8006
- n_vals: 2
- n_keys: 1
- n_fields: 3
- val fields:
- hist_data->fields[0]:
- flags:
- VAL: HIST_FIELD_FL_HITCOUNT
- type: u64
- size: 8
- is_signed: 0
- hist_data->fields[1]:
- flags:
- HIST_FIELD_FL_VAR
- var.name: wakeup_lat
- var.idx (into tracing_map_elt.vars[]): 0
- type: u64
- size: 0
- is_signed: 0
- key fields:
- hist_data->fields[2]:
- flags:
- HIST_FIELD_FL_KEY
- ftrace_event_field name: next_pid
- type: pid_t
- size: 8
- is_signed: 1
- variable reference fields:
- hist_data->var_refs[0]:
- flags:
- HIST_FIELD_FL_VAR_REF
- name: ts0
- var.idx (into tracing_map_elt.vars[]): 0
- var.hist_data: 000000009536f554
- var_ref_idx (into hist_data->var_refs[]): 0
- type: u64
- size: 8
- is_signed: 0
- The commands below can be used to clean things up for the next test::
- # echo '!hist:keys=next_pid:wakeup_lat=common_timestamp.usecs-$ts0' >> events/sched/sched_switch/trigger
- # echo '!hist:keys=pid:ts0=common_timestamp.usecs' >> events/sched/sched_waking/trigger
- Actions and Handlers
- ====================
- Adding onto the previous example, we will now do something with that
- wakeup_lat variable, namely send it and another field as a synthetic
- event.
- The onmatch() action below basically says that whenever we have a
- sched_switch event, if we have a matching sched_waking event, in this
- case if we have a pid in the sched_waking histogram that matches the
- next_pid field on this sched_switch event, we retrieve the
- variables specified in the wakeup_latency() trace action, and use
- them to generate a new wakeup_latency event into the trace stream.
- Note that the way the trace handlers such as wakeup_latency() (which
- could equivalently be written trace(wakeup_latency,$wakeup_lat,next_pid)
- are implemented, the parameters specified to the trace handler must be
- variables. In this case, $wakeup_lat is obviously a variable, but
- next_pid isn't, since it's just naming a field in the sched_switch
- trace event. Since this is something that almost every trace() and
- save() action does, a special shortcut is implemented to allow field
- names to be used directly in those cases. How it works is that under
- the covers, a temporary variable is created for the named field, and
- this variable is what is actually passed to the trace handler. In the
- code and documentation, this type of variable is called a 'field
- variable'.
- Fields on other trace event's histograms can be used as well. In that
- case we have to generate a new histogram and an unfortunately named
- 'synthetic_field' (the use of synthetic here has nothing to do with
- synthetic events) and use that special histogram field as a variable.
- The diagram below illustrates the new elements described above in the
- context of the sched_switch histogram using the onmatch() handler and
- the trace() action.
- First, we define the wakeup_latency synthetic event::
- # echo 'wakeup_latency u64 lat; pid_t pid' >> synthetic_events
- Next, the sched_waking hist trigger as before::
- # echo 'hist:keys=pid:ts0=common_timestamp.usecs' >>
- events/sched/sched_waking/trigger
- Finally, we create a hist trigger on the sched_switch event that
- generates a wakeup_latency() trace event. In this case we pass
- next_pid into the wakeup_latency synthetic event invocation, which
- means it will be automatically converted into a field variable::
- # echo 'hist:keys=next_pid:wakeup_lat=common_timestamp.usecs-$ts0: \
- onmatch(sched.sched_waking).wakeup_latency($wakeup_lat,next_pid)' >>
- /sys/kernel/debug/tracing/events/sched/sched_switch/trigger
- The diagram for the sched_switch event is similar to previous examples
- but shows the additional field_vars[] array for hist_data and shows
- the linkages between the field_vars and the variables and references
- created to implement the field variables. The details are discussed
- below::
- +------------------+
- | hist_data |
- +------------------+ +-----------------------+
- | .fields[] |-->| val = hitcount |
- +----------------+ +-----------------------+
- | .map | | .size |
- +----------------+ +---------------------+
- +---| .field_vars[] | | .offset |
- | +----------------+ +---------------------+
- |+--| .var_refs[] | | .offset |
- || +----------------+ +---------------------+
- || | .fn() |
- || var_ref_vals[] +---------------------+
- || +-------------+ | .flags |
- || | $ts0 |<---+ +---------------------+
- || +-------------+ | | .var.idx |
- || | $next_pid |<-+ | +---------------------+
- || +-------------+ | | | .var.hist_data |
- ||+>| $wakeup_lat | | | +---------------------+
- ||| +-------------+ | | | .var_ref_idx |
- ||| | | | | +-----------------------+
- ||| +-------------+ | | | var = wakeup_lat |
- ||| . | | +-----------------------+
- ||| . | | | .size |
- ||| . | | +---------------------+
- ||| +-------------+ | | | .offset |
- ||| | | | | +---------------------+
- ||| +-------------+ | | | .fn() |
- ||| | | | | +---------------------+
- ||| +-------------+ | | | .flags & FL_VAR |
- ||| | | +---------------------+
- ||| | | | .var.idx |
- ||| | | +---------------------+
- ||| | | | .var.hist_data |
- ||| | | +---------------------+
- ||| | | | .var_ref_idx |
- ||| | | +---------------------+
- ||| | | .
- ||| | | .
- ||| | | .
- ||| | | .
- ||| +--------------+ | | .
- +-->| field_var | | | .
- || +--------------+ | | .
- || | var | | | .
- || +------------+ | | .
- || | val | | | .
- || +--------------+ | | .
- || | field_var | | | .
- || +--------------+ | | .
- || | var | | | .
- || +------------+ | | .
- || | val | | | .
- || +------------+ | | .
- || . | | .
- || . | | .
- || . | | +-----------------------+ <--- n_vals
- || +--------------+ | | | key = pid |
- || | field_var | | | +-----------------------+
- || +--------------+ | | | .size |
- || | var |--+| +---------------------+
- || +------------+ ||| | .offset |
- || | val |-+|| +---------------------+
- || +------------+ ||| | .fn() |
- || ||| +---------------------+
- || ||| | .flags |
- || ||| +---------------------+
- || ||| | .var.idx |
- || ||| +---------------------+ <--- n_fields
- || |||
- || ||| n_keys = n_fields - n_vals
- || ||| +-----------------------+
- || |+->| var = next_pid |
- || | | +-----------------------+
- || | | | .size |
- || | | +---------------------+
- || | | | .offset |
- || | | +---------------------+
- || | | | .flags & FL_VAR |
- || | | +---------------------+
- || | | | .var.idx |
- || | | +---------------------+
- || | | | .var.hist_data |
- || | | +-----------------------+
- || +-->| val for next_pid |
- || | | +-----------------------+
- || | | | .size |
- || | | +---------------------+
- || | | | .offset |
- || | | +---------------------+
- || | | | .fn() |
- || | | +---------------------+
- || | | | .flags |
- || | | +---------------------+
- || | | | |
- || | | +---------------------+
- || | |
- || | |
- || | | +-----------------------+
- +|------------------|-|>| var_ref = $ts0 |
- | | | +-----------------------+
- | | | | .size |
- | | | +---------------------+
- | | | | .offset |
- | | | +---------------------+
- | | | | .fn() |
- | | | +---------------------+
- | | | | .flags & FL_VAR_REF |
- | | | +---------------------+
- | | +---| .var_ref_idx |
- | | +-----------------------+
- | | | var_ref = $next_pid |
- | | +-----------------------+
- | | | .size |
- | | +---------------------+
- | | | .offset |
- | | +---------------------+
- | | | .fn() |
- | | +---------------------+
- | | | .flags & FL_VAR_REF |
- | | +---------------------+
- | +-----| .var_ref_idx |
- | +-----------------------+
- | | var_ref = $wakeup_lat |
- | +-----------------------+
- | | .size |
- | +---------------------+
- | | .offset |
- | +---------------------+
- | | .fn() |
- | +---------------------+
- | | .flags & FL_VAR_REF |
- | +---------------------+
- +------------------------| .var_ref_idx |
- +---------------------+
- As you can see, for a field variable, two hist_fields are created: one
- representing the variable, in this case next_pid, and one to actually
- get the value of the field from the trace stream, like a normal val
- field does. These are created separately from normal variable
- creation and are saved in the hist_data->field_vars[] array. See
- below for how these are used. In addition, a reference hist_field is
- also created, which is needed to reference the field variables such as
- $next_pid variable in the trace() action.
- Note that $wakeup_lat is also a variable reference, referencing the
- value of the expression common_timestamp-$ts0, and so also needs to
- have a hist field entry representing that reference created.
- When hist_trigger_elt_update() is called to get the normal key and
- value fields, it also calls update_field_vars(), which goes through
- each field_var created for the histogram, and available from
- hist_data->field_vars and calls val->fn() to get the data from the
- current trace record, and then uses the var's var.idx to set the
- variable at the var.idx offset in the appropriate tracing_map_elt's
- variable at elt->vars[var.idx].
- Once all the variables have been updated, resolve_var_refs() can be
- called from event_hist_trigger(), and not only can our $ts0 and
- $next_pid references be resolved but the $wakeup_lat reference as
- well. At this point, the trace() action can simply access the values
- assembled in the var_ref_vals[] array and generate the trace event.
- The same process occurs for the field variables associated with the
- save() action.
- Abbreviations used in the diagram::
- hist_data = struct hist_trigger_data
- hist_data.fields = struct hist_field
- field_var = struct field_var
- fn = hist_field_fn_t
- FL_KEY = HIST_FIELD_FL_KEY
- FL_VAR = HIST_FIELD_FL_VAR
- FL_VAR_REF = HIST_FIELD_FL_VAR_REF
- trace() action field variable test
- ----------------------------------
- This example adds to the previous test example by finally making use
- of the wakeup_lat variable, but in addition also creates a couple of
- field variables that then are all passed to the wakeup_latency() trace
- action via the onmatch() handler.
- First, we create the wakeup_latency synthetic event::
- # echo 'wakeup_latency u64 lat; pid_t pid; char comm[16]' >> synthetic_events
- Next, the sched_waking trigger from previous examples::
- # echo 'hist:keys=pid:ts0=common_timestamp.usecs' >> events/sched/sched_waking/trigger
- Finally, as in the previous test example, we calculate and assign the
- wakeup latency using the $ts0 reference from the sched_waking trigger
- to the wakeup_lat variable, and finally use it along with a couple
- sched_switch event fields, next_pid and next_comm, to generate a
- wakeup_latency trace event. The next_pid and next_comm event fields
- are automatically converted into field variables for this purpose::
- # echo 'hist:keys=next_pid:wakeup_lat=common_timestamp.usecs-$ts0:onmatch(sched.sched_waking).wakeup_latency($wakeup_lat,next_pid,next_comm)' >> /sys/kernel/debug/tracing/events/sched/sched_switch/trigger
- The sched_waking hist_debug output shows the same data as in the
- previous test example::
- # cat events/sched/sched_waking/hist_debug
- # event histogram
- #
- # trigger info: hist:keys=pid:vals=hitcount:ts0=common_timestamp.usecs:sort=hitcount:size=2048:clock=global [active]
- #
- hist_data: 00000000d60ff61f
- n_vals: 2
- n_keys: 1
- n_fields: 3
- val fields:
- hist_data->fields[0]:
- flags:
- VAL: HIST_FIELD_FL_HITCOUNT
- type: u64
- size: 8
- is_signed: 0
- hist_data->fields[1]:
- flags:
- HIST_FIELD_FL_VAR
- var.name: ts0
- var.idx (into tracing_map_elt.vars[]): 0
- type: u64
- size: 8
- is_signed: 0
- key fields:
- hist_data->fields[2]:
- flags:
- HIST_FIELD_FL_KEY
- ftrace_event_field name: pid
- type: pid_t
- size: 8
- is_signed: 1
- The sched_switch hist_debug output shows the same key and value fields
- as in the previous test example - note that wakeup_lat is still in the
- val fields section, but that the new field variables are not there -
- although the field variables are variables, they're held separately in
- the hist_data's field_vars[] array. Although the field variables and
- the normal variables are located in separate places, you can see that
- the actual variable locations for those variables in the
- tracing_map_elt.vars[] do have increasing indices as expected:
- wakeup_lat takes the var.idx = 0 slot, while the field variables for
- next_pid and next_comm have values var.idx = 1, and var.idx = 2. Note
- also that those are the same values displayed for the variable
- references corresponding to those variables in the variable reference
- fields section. Since there are two triggers and thus two hist_data
- addresses, those addresses also need to be accounted for when doing
- the matching - you can see that the first variable refers to the 0
- var.idx on the previous hist trigger (see the hist_data address
- associated with that trigger), while the second variable refers to the
- 0 var.idx on the sched_switch hist trigger, as do all the remaining
- variable references.
- Finally, the action tracking variables section just shows the system
- and event name for the onmatch() handler::
- # cat events/sched/sched_switch/hist_debug
- # event histogram
- #
- # trigger info: hist:keys=next_pid:vals=hitcount:wakeup_lat=common_timestamp.usecs-$ts0:sort=hitcount:size=2048:clock=global:onmatch(sched.sched_waking).wakeup_latency($wakeup_lat,next_pid,next_comm) [active]
- #
- hist_data: 0000000008f551b7
- n_vals: 2
- n_keys: 1
- n_fields: 3
- val fields:
- hist_data->fields[0]:
- flags:
- VAL: HIST_FIELD_FL_HITCOUNT
- type: u64
- size: 8
- is_signed: 0
- hist_data->fields[1]:
- flags:
- HIST_FIELD_FL_VAR
- var.name: wakeup_lat
- var.idx (into tracing_map_elt.vars[]): 0
- type: u64
- size: 0
- is_signed: 0
- key fields:
- hist_data->fields[2]:
- flags:
- HIST_FIELD_FL_KEY
- ftrace_event_field name: next_pid
- type: pid_t
- size: 8
- is_signed: 1
- variable reference fields:
- hist_data->var_refs[0]:
- flags:
- HIST_FIELD_FL_VAR_REF
- name: ts0
- var.idx (into tracing_map_elt.vars[]): 0
- var.hist_data: 00000000d60ff61f
- var_ref_idx (into hist_data->var_refs[]): 0
- type: u64
- size: 8
- is_signed: 0
- hist_data->var_refs[1]:
- flags:
- HIST_FIELD_FL_VAR_REF
- name: wakeup_lat
- var.idx (into tracing_map_elt.vars[]): 0
- var.hist_data: 0000000008f551b7
- var_ref_idx (into hist_data->var_refs[]): 1
- type: u64
- size: 0
- is_signed: 0
- hist_data->var_refs[2]:
- flags:
- HIST_FIELD_FL_VAR_REF
- name: next_pid
- var.idx (into tracing_map_elt.vars[]): 1
- var.hist_data: 0000000008f551b7
- var_ref_idx (into hist_data->var_refs[]): 2
- type: pid_t
- size: 4
- is_signed: 0
- hist_data->var_refs[3]:
- flags:
- HIST_FIELD_FL_VAR_REF
- name: next_comm
- var.idx (into tracing_map_elt.vars[]): 2
- var.hist_data: 0000000008f551b7
- var_ref_idx (into hist_data->var_refs[]): 3
- type: char[16]
- size: 256
- is_signed: 0
- field variables:
- hist_data->field_vars[0]:
- field_vars[0].var:
- flags:
- HIST_FIELD_FL_VAR
- var.name: next_pid
- var.idx (into tracing_map_elt.vars[]): 1
- field_vars[0].val:
- ftrace_event_field name: next_pid
- type: pid_t
- size: 4
- is_signed: 1
- hist_data->field_vars[1]:
- field_vars[1].var:
- flags:
- HIST_FIELD_FL_VAR
- var.name: next_comm
- var.idx (into tracing_map_elt.vars[]): 2
- field_vars[1].val:
- ftrace_event_field name: next_comm
- type: char[16]
- size: 256
- is_signed: 0
- action tracking variables (for onmax()/onchange()/onmatch()):
- hist_data->actions[0].match_data.event_system: sched
- hist_data->actions[0].match_data.event: sched_waking
- The commands below can be used to clean things up for the next test::
- # echo '!hist:keys=next_pid:wakeup_lat=common_timestamp.usecs-$ts0:onmatch(sched.sched_waking).wakeup_latency($wakeup_lat,next_pid,next_comm)' >> /sys/kernel/debug/tracing/events/sched/sched_switch/trigger
- # echo '!hist:keys=pid:ts0=common_timestamp.usecs' >> events/sched/sched_waking/trigger
- # echo '!wakeup_latency u64 lat; pid_t pid; char comm[16]' >> synthetic_events
- action_data and the trace() action
- ----------------------------------
- As mentioned above, when the trace() action generates a synthetic
- event, all the parameters to the synthetic event either already are
- variables or are converted into variables (via field variables), and
- finally all those variable values are collected via references to them
- into a var_ref_vals[] array.
- The values in the var_ref_vals[] array, however, don't necessarily
- follow the same ordering as the synthetic event params. To address
- that, struct action_data contains another array, var_ref_idx[] that
- maps the trace action params to the var_ref_vals[] values. Below is a
- diagram illustrating that for the wakeup_latency() synthetic event::
- +------------------+ wakeup_latency()
- | action_data | event params var_ref_vals[]
- +------------------+ +-----------------+ +-----------------+
- | .var_ref_idx[] |--->| $wakeup_lat idx |---+ | |
- +----------------+ +-----------------+ | +-----------------+
- | .synth_event | | $next_pid idx |---|-+ | $wakeup_lat val |
- +----------------+ +-----------------+ | | +-----------------+
- . | +->| $next_pid val |
- . | +-----------------+
- . | .
- +-----------------+ | .
- | | | .
- +-----------------+ | +-----------------+
- +--->| $wakeup_lat val |
- +-----------------+
- Basically, how this ends up getting used in the synthetic event probe
- function, trace_event_raw_event_synth(), is as follows::
- for each field i in .synth_event
- val_idx = .var_ref_idx[i]
- val = var_ref_vals[val_idx]
- action_data and the onXXX() handlers
- ------------------------------------
- The hist trigger onXXX() actions other than onmatch(), such as onmax()
- and onchange(), also make use of and internally create hidden
- variables. This information is contained in the
- action_data.track_data struct, and is also visible in the hist_debug
- output as will be described in the example below.
- Typically, the onmax() or onchange() handlers are used in conjunction
- with the save() and snapshot() actions. For example::
- # echo 'hist:keys=next_pid:wakeup_lat=common_timestamp.usecs-$ts0: \
- onmax($wakeup_lat).save(next_comm,prev_pid,prev_prio,prev_comm)' >>
- /sys/kernel/debug/tracing/events/sched/sched_switch/trigger
- or::
- # echo 'hist:keys=next_pid:wakeup_lat=common_timestamp.usecs-$ts0: \
- onmax($wakeup_lat).snapshot()' >>
- /sys/kernel/debug/tracing/events/sched/sched_switch/trigger
- save() action field variable test
- ---------------------------------
- For this example, instead of generating a synthetic event, the save()
- action is used to save field values whenever an onmax() handler
- detects that a new max latency has been hit. As in the previous
- example, the values being saved are also field values, but in this
- case, are kept in a separate hist_data array named save_vars[].
- As in previous test examples, we set up the sched_waking trigger::
- # echo 'hist:keys=pid:ts0=common_timestamp.usecs' >> events/sched/sched_waking/trigger
- In this case, however, we set up the sched_switch trigger to save some
- sched_switch field values whenever we hit a new maximum latency. For
- both the onmax() handler and save() action, variables will be created,
- which we can use the hist_debug files to examine::
- # echo 'hist:keys=next_pid:wakeup_lat=common_timestamp.usecs-$ts0:onmax($wakeup_lat).save(next_comm,prev_pid,prev_prio,prev_comm)' >> events/sched/sched_switch/trigger
- The sched_waking hist_debug output shows the same data as in the
- previous test examples::
- # cat events/sched/sched_waking/hist_debug
- #
- # trigger info: hist:keys=pid:vals=hitcount:ts0=common_timestamp.usecs:sort=hitcount:size=2048:clock=global [active]
- #
- hist_data: 00000000e6290f48
- n_vals: 2
- n_keys: 1
- n_fields: 3
- val fields:
- hist_data->fields[0]:
- flags:
- VAL: HIST_FIELD_FL_HITCOUNT
- type: u64
- size: 8
- is_signed: 0
- hist_data->fields[1]:
- flags:
- HIST_FIELD_FL_VAR
- var.name: ts0
- var.idx (into tracing_map_elt.vars[]): 0
- type: u64
- size: 8
- is_signed: 0
- key fields:
- hist_data->fields[2]:
- flags:
- HIST_FIELD_FL_KEY
- ftrace_event_field name: pid
- type: pid_t
- size: 8
- is_signed: 1
- The output of the sched_switch trigger shows the same val and key
- values as before, but also shows a couple new sections.
- First, the action tracking variables section now shows the
- actions[].track_data information describing the special tracking
- variables and references used to track, in this case, the running
- maximum value. The actions[].track_data.var_ref member contains the
- reference to the variable being tracked, in this case the $wakeup_lat
- variable. In order to perform the onmax() handler function, there
- also needs to be a variable that tracks the current maximum by getting
- updated whenever a new maximum is hit. In this case, we can see that
- an auto-generated variable named ' __max' has been created and is
- visible in the actions[].track_data.track_var variable.
- Finally, in the new 'save action variables' section, we can see that
- the 4 params to the save() function have resulted in 4 field variables
- being created for the purposes of saving the values of the named
- fields when the max is hit. These variables are kept in a separate
- save_vars[] array off of hist_data, so are displayed in a separate
- section::
- # cat events/sched/sched_switch/hist_debug
- # event histogram
- #
- # trigger info: hist:keys=next_pid:vals=hitcount:wakeup_lat=common_timestamp.usecs-$ts0:sort=hitcount:size=2048:clock=global:onmax($wakeup_lat).save(next_comm,prev_pid,prev_prio,prev_comm) [active]
- #
- hist_data: 0000000057bcd28d
- n_vals: 2
- n_keys: 1
- n_fields: 3
- val fields:
- hist_data->fields[0]:
- flags:
- VAL: HIST_FIELD_FL_HITCOUNT
- type: u64
- size: 8
- is_signed: 0
- hist_data->fields[1]:
- flags:
- HIST_FIELD_FL_VAR
- var.name: wakeup_lat
- var.idx (into tracing_map_elt.vars[]): 0
- type: u64
- size: 0
- is_signed: 0
- key fields:
- hist_data->fields[2]:
- flags:
- HIST_FIELD_FL_KEY
- ftrace_event_field name: next_pid
- type: pid_t
- size: 8
- is_signed: 1
- variable reference fields:
- hist_data->var_refs[0]:
- flags:
- HIST_FIELD_FL_VAR_REF
- name: ts0
- var.idx (into tracing_map_elt.vars[]): 0
- var.hist_data: 00000000e6290f48
- var_ref_idx (into hist_data->var_refs[]): 0
- type: u64
- size: 8
- is_signed: 0
- hist_data->var_refs[1]:
- flags:
- HIST_FIELD_FL_VAR_REF
- name: wakeup_lat
- var.idx (into tracing_map_elt.vars[]): 0
- var.hist_data: 0000000057bcd28d
- var_ref_idx (into hist_data->var_refs[]): 1
- type: u64
- size: 0
- is_signed: 0
- action tracking variables (for onmax()/onchange()/onmatch()):
- hist_data->actions[0].track_data.var_ref:
- flags:
- HIST_FIELD_FL_VAR_REF
- name: wakeup_lat
- var.idx (into tracing_map_elt.vars[]): 0
- var.hist_data: 0000000057bcd28d
- var_ref_idx (into hist_data->var_refs[]): 1
- type: u64
- size: 0
- is_signed: 0
- hist_data->actions[0].track_data.track_var:
- flags:
- HIST_FIELD_FL_VAR
- var.name: __max
- var.idx (into tracing_map_elt.vars[]): 1
- type: u64
- size: 8
- is_signed: 0
- save action variables (save() params):
- hist_data->save_vars[0]:
- save_vars[0].var:
- flags:
- HIST_FIELD_FL_VAR
- var.name: next_comm
- var.idx (into tracing_map_elt.vars[]): 2
- save_vars[0].val:
- ftrace_event_field name: next_comm
- type: char[16]
- size: 256
- is_signed: 0
- hist_data->save_vars[1]:
- save_vars[1].var:
- flags:
- HIST_FIELD_FL_VAR
- var.name: prev_pid
- var.idx (into tracing_map_elt.vars[]): 3
- save_vars[1].val:
- ftrace_event_field name: prev_pid
- type: pid_t
- size: 4
- is_signed: 1
- hist_data->save_vars[2]:
- save_vars[2].var:
- flags:
- HIST_FIELD_FL_VAR
- var.name: prev_prio
- var.idx (into tracing_map_elt.vars[]): 4
- save_vars[2].val:
- ftrace_event_field name: prev_prio
- type: int
- size: 4
- is_signed: 1
- hist_data->save_vars[3]:
- save_vars[3].var:
- flags:
- HIST_FIELD_FL_VAR
- var.name: prev_comm
- var.idx (into tracing_map_elt.vars[]): 5
- save_vars[3].val:
- ftrace_event_field name: prev_comm
- type: char[16]
- size: 256
- is_signed: 0
- The commands below can be used to clean things up for the next test::
- # echo '!hist:keys=next_pid:wakeup_lat=common_timestamp.usecs-$ts0:onmax($wakeup_lat).save(next_comm,prev_pid,prev_prio,prev_comm)' >> events/sched/sched_switch/trigger
- # echo '!hist:keys=pid:ts0=common_timestamp.usecs' >> events/sched/sched_waking/trigger
- A couple special cases
- ======================
- While the above covers the basics of the histogram internals, there
- are a couple of special cases that should be discussed, since they
- tend to create even more confusion. Those are field variables on other
- histograms, and aliases, both described below through example tests
- using the hist_debug files.
- Test of field variables on other histograms
- -------------------------------------------
- This example is similar to the previous examples, but in this case,
- the sched_switch trigger references a hist trigger field on another
- event, namely the sched_waking event. In order to accomplish this, a
- field variable is created for the other event, but since an existing
- histogram can't be used, as existing histograms are immutable, a new
- histogram with a matching variable is created and used, and we'll see
- that reflected in the hist_debug output shown below.
- First, we create the wakeup_latency synthetic event. Note the
- addition of the prio field::
- # echo 'wakeup_latency u64 lat; pid_t pid; int prio' >> synthetic_events
- As in previous test examples, we set up the sched_waking trigger::
- # echo 'hist:keys=pid:ts0=common_timestamp.usecs' >> events/sched/sched_waking/trigger
- Here we set up a hist trigger on sched_switch to send a wakeup_latency
- event using an onmatch handler naming the sched_waking event. Note
- that the third param being passed to the wakeup_latency() is prio,
- which is a field name that needs to have a field variable created for
- it. There isn't however any prio field on the sched_switch event so
- it would seem that it wouldn't be possible to create a field variable
- for it. The matching sched_waking event does have a prio field, so it
- should be possible to make use of it for this purpose. The problem
- with that is that it's not currently possible to define a new variable
- on an existing histogram, so it's not possible to add a new prio field
- variable to the existing sched_waking histogram. It is however
- possible to create an additional new 'matching' sched_waking histogram
- for the same event, meaning that it uses the same key and filters, and
- define the new prio field variable on that.
- Here's the sched_switch trigger::
- # echo 'hist:keys=next_pid:wakeup_lat=common_timestamp.usecs-$ts0:onmatch(sched.sched_waking).wakeup_latency($wakeup_lat,next_pid,prio)' >> events/sched/sched_switch/trigger
- And here's the output of the hist_debug information for the
- sched_waking hist trigger. Note that there are two histograms
- displayed in the output: the first is the normal sched_waking
- histogram we've seen in the previous examples, and the second is the
- special histogram we created to provide the prio field variable.
- Looking at the second histogram below, we see a variable with the name
- synthetic_prio. This is the field variable created for the prio field
- on that sched_waking histogram::
- # cat events/sched/sched_waking/hist_debug
- # event histogram
- #
- # trigger info: hist:keys=pid:vals=hitcount:ts0=common_timestamp.usecs:sort=hitcount:size=2048:clock=global [active]
- #
- hist_data: 00000000349570e4
- n_vals: 2
- n_keys: 1
- n_fields: 3
- val fields:
- hist_data->fields[0]:
- flags:
- VAL: HIST_FIELD_FL_HITCOUNT
- type: u64
- size: 8
- is_signed: 0
- hist_data->fields[1]:
- flags:
- HIST_FIELD_FL_VAR
- var.name: ts0
- var.idx (into tracing_map_elt.vars[]): 0
- type: u64
- size: 8
- is_signed: 0
- key fields:
- hist_data->fields[2]:
- flags:
- HIST_FIELD_FL_KEY
- ftrace_event_field name: pid
- type: pid_t
- size: 8
- is_signed: 1
- # event histogram
- #
- # trigger info: hist:keys=pid:vals=hitcount:synthetic_prio=prio:sort=hitcount:size=2048 [active]
- #
- hist_data: 000000006920cf38
- n_vals: 2
- n_keys: 1
- n_fields: 3
- val fields:
- hist_data->fields[0]:
- flags:
- VAL: HIST_FIELD_FL_HITCOUNT
- type: u64
- size: 8
- is_signed: 0
- hist_data->fields[1]:
- flags:
- HIST_FIELD_FL_VAR
- ftrace_event_field name: prio
- var.name: synthetic_prio
- var.idx (into tracing_map_elt.vars[]): 0
- type: int
- size: 4
- is_signed: 1
- key fields:
- hist_data->fields[2]:
- flags:
- HIST_FIELD_FL_KEY
- ftrace_event_field name: pid
- type: pid_t
- size: 8
- is_signed: 1
- Looking at the sched_switch histogram below, we can see a reference to
- the synthetic_prio variable on sched_waking, and looking at the
- associated hist_data address we see that it is indeed associated with
- the new histogram. Note also that the other references are to a
- normal variable, wakeup_lat, and to a normal field variable, next_pid,
- the details of which are in the field variables section::
- # cat events/sched/sched_switch/hist_debug
- # event histogram
- #
- # trigger info: hist:keys=next_pid:vals=hitcount:wakeup_lat=common_timestamp.usecs-$ts0:sort=hitcount:size=2048:clock=global:onmatch(sched.sched_waking).wakeup_latency($wakeup_lat,next_pid,prio) [active]
- #
- hist_data: 00000000a73b67df
- n_vals: 2
- n_keys: 1
- n_fields: 3
- val fields:
- hist_data->fields[0]:
- flags:
- VAL: HIST_FIELD_FL_HITCOUNT
- type: u64
- size: 8
- is_signed: 0
- hist_data->fields[1]:
- flags:
- HIST_FIELD_FL_VAR
- var.name: wakeup_lat
- var.idx (into tracing_map_elt.vars[]): 0
- type: u64
- size: 0
- is_signed: 0
- key fields:
- hist_data->fields[2]:
- flags:
- HIST_FIELD_FL_KEY
- ftrace_event_field name: next_pid
- type: pid_t
- size: 8
- is_signed: 1
- variable reference fields:
- hist_data->var_refs[0]:
- flags:
- HIST_FIELD_FL_VAR_REF
- name: ts0
- var.idx (into tracing_map_elt.vars[]): 0
- var.hist_data: 00000000349570e4
- var_ref_idx (into hist_data->var_refs[]): 0
- type: u64
- size: 8
- is_signed: 0
- hist_data->var_refs[1]:
- flags:
- HIST_FIELD_FL_VAR_REF
- name: wakeup_lat
- var.idx (into tracing_map_elt.vars[]): 0
- var.hist_data: 00000000a73b67df
- var_ref_idx (into hist_data->var_refs[]): 1
- type: u64
- size: 0
- is_signed: 0
- hist_data->var_refs[2]:
- flags:
- HIST_FIELD_FL_VAR_REF
- name: next_pid
- var.idx (into tracing_map_elt.vars[]): 1
- var.hist_data: 00000000a73b67df
- var_ref_idx (into hist_data->var_refs[]): 2
- type: pid_t
- size: 4
- is_signed: 0
- hist_data->var_refs[3]:
- flags:
- HIST_FIELD_FL_VAR_REF
- name: synthetic_prio
- var.idx (into tracing_map_elt.vars[]): 0
- var.hist_data: 000000006920cf38
- var_ref_idx (into hist_data->var_refs[]): 3
- type: int
- size: 4
- is_signed: 1
- field variables:
- hist_data->field_vars[0]:
- field_vars[0].var:
- flags:
- HIST_FIELD_FL_VAR
- var.name: next_pid
- var.idx (into tracing_map_elt.vars[]): 1
- field_vars[0].val:
- ftrace_event_field name: next_pid
- type: pid_t
- size: 4
- is_signed: 1
- action tracking variables (for onmax()/onchange()/onmatch()):
- hist_data->actions[0].match_data.event_system: sched
- hist_data->actions[0].match_data.event: sched_waking
- The commands below can be used to clean things up for the next test::
- # echo '!hist:keys=next_pid:wakeup_lat=common_timestamp.usecs-$ts0:onmatch(sched.sched_waking).wakeup_latency($wakeup_lat,next_pid,prio)' >> events/sched/sched_switch/trigger
- # echo '!hist:keys=pid:ts0=common_timestamp.usecs' >> events/sched/sched_waking/trigger
- # echo '!wakeup_latency u64 lat; pid_t pid; int prio' >> synthetic_events
- Alias test
- ----------
- This example is very similar to previous examples, but demonstrates
- the alias flag.
- First, we create the wakeup_latency synthetic event::
- # echo 'wakeup_latency u64 lat; pid_t pid; char comm[16]' >> synthetic_events
- Next, we create a sched_waking trigger similar to previous examples,
- but in this case we save the pid in the waking_pid variable::
- # echo 'hist:keys=pid:waking_pid=pid:ts0=common_timestamp.usecs' >> events/sched/sched_waking/trigger
- For the sched_switch trigger, instead of using $waking_pid directly in
- the wakeup_latency synthetic event invocation, we create an alias of
- $waking_pid named $woken_pid, and use that in the synthetic event
- invocation instead::
- # echo 'hist:keys=next_pid:woken_pid=$waking_pid:wakeup_lat=common_timestamp.usecs-$ts0:onmatch(sched.sched_waking).wakeup_latency($wakeup_lat,$woken_pid,next_comm)' >> events/sched/sched_switch/trigger
- Looking at the sched_waking hist_debug output, in addition to the
- normal fields, we can see the waking_pid variable::
- # cat events/sched/sched_waking/hist_debug
- # event histogram
- #
- # trigger info: hist:keys=pid:vals=hitcount:waking_pid=pid,ts0=common_timestamp.usecs:sort=hitcount:size=2048:clock=global [active]
- #
- hist_data: 00000000a250528c
- n_vals: 3
- n_keys: 1
- n_fields: 4
- val fields:
- hist_data->fields[0]:
- flags:
- VAL: HIST_FIELD_FL_HITCOUNT
- type: u64
- size: 8
- is_signed: 0
- hist_data->fields[1]:
- flags:
- HIST_FIELD_FL_VAR
- ftrace_event_field name: pid
- var.name: waking_pid
- var.idx (into tracing_map_elt.vars[]): 0
- type: pid_t
- size: 4
- is_signed: 1
- hist_data->fields[2]:
- flags:
- HIST_FIELD_FL_VAR
- var.name: ts0
- var.idx (into tracing_map_elt.vars[]): 1
- type: u64
- size: 8
- is_signed: 0
- key fields:
- hist_data->fields[3]:
- flags:
- HIST_FIELD_FL_KEY
- ftrace_event_field name: pid
- type: pid_t
- size: 8
- is_signed: 1
- The sched_switch hist_debug output shows that a variable named
- woken_pid has been created but that it also has the
- HIST_FIELD_FL_ALIAS flag set. It also has the HIST_FIELD_FL_VAR flag
- set, which is why it appears in the val field section.
- Despite that implementation detail, an alias variable is actually more
- like a variable reference; in fact it can be thought of as a reference
- to a reference. The implementation copies the var_ref->fn() from the
- variable reference being referenced, in this case, the waking_pid
- fn(), which is hist_field_var_ref() and makes that the fn() of the
- alias. The hist_field_var_ref() fn() requires the var_ref_idx of the
- variable reference it's using, so waking_pid's var_ref_idx is also
- copied to the alias. The end result is that when the value of alias
- is retrieved, in the end it just does the same thing the original
- reference would have done and retrieves the same value from the
- var_ref_vals[] array. You can verify this in the output by noting
- that the var_ref_idx of the alias, in this case woken_pid, is the same
- as the var_ref_idx of the reference, waking_pid, in the variable
- reference fields section.
- Additionally, once it gets that value, since it is also a variable, it
- then saves that value into its var.idx. So the var.idx of the
- woken_pid alias is 0, which it fills with the value from var_ref_idx 0
- when its fn() is called to update itself. You'll also notice that
- there's a woken_pid var_ref in the variable refs section. That is the
- reference to the woken_pid alias variable, and you can see that it
- retrieves the value from the same var.idx as the woken_pid alias, 0,
- and then in turn saves that value in its own var_ref_idx slot, 3, and
- the value at this position is finally what gets assigned to the
- $woken_pid slot in the trace event invocation::
- # cat events/sched/sched_switch/hist_debug
- # event histogram
- #
- # trigger info: hist:keys=next_pid:vals=hitcount:woken_pid=$waking_pid,wakeup_lat=common_timestamp.usecs-$ts0:sort=hitcount:size=2048:clock=global:onmatch(sched.sched_waking).wakeup_latency($wakeup_lat,$woken_pid,next_comm) [active]
- #
- hist_data: 0000000055d65ed0
- n_vals: 3
- n_keys: 1
- n_fields: 4
- val fields:
- hist_data->fields[0]:
- flags:
- VAL: HIST_FIELD_FL_HITCOUNT
- type: u64
- size: 8
- is_signed: 0
- hist_data->fields[1]:
- flags:
- HIST_FIELD_FL_VAR
- HIST_FIELD_FL_ALIAS
- var.name: woken_pid
- var.idx (into tracing_map_elt.vars[]): 0
- var_ref_idx (into hist_data->var_refs[]): 0
- type: pid_t
- size: 4
- is_signed: 1
- hist_data->fields[2]:
- flags:
- HIST_FIELD_FL_VAR
- var.name: wakeup_lat
- var.idx (into tracing_map_elt.vars[]): 1
- type: u64
- size: 0
- is_signed: 0
- key fields:
- hist_data->fields[3]:
- flags:
- HIST_FIELD_FL_KEY
- ftrace_event_field name: next_pid
- type: pid_t
- size: 8
- is_signed: 1
- variable reference fields:
- hist_data->var_refs[0]:
- flags:
- HIST_FIELD_FL_VAR_REF
- name: waking_pid
- var.idx (into tracing_map_elt.vars[]): 0
- var.hist_data: 00000000a250528c
- var_ref_idx (into hist_data->var_refs[]): 0
- type: pid_t
- size: 4
- is_signed: 1
- hist_data->var_refs[1]:
- flags:
- HIST_FIELD_FL_VAR_REF
- name: ts0
- var.idx (into tracing_map_elt.vars[]): 1
- var.hist_data: 00000000a250528c
- var_ref_idx (into hist_data->var_refs[]): 1
- type: u64
- size: 8
- is_signed: 0
- hist_data->var_refs[2]:
- flags:
- HIST_FIELD_FL_VAR_REF
- name: wakeup_lat
- var.idx (into tracing_map_elt.vars[]): 1
- var.hist_data: 0000000055d65ed0
- var_ref_idx (into hist_data->var_refs[]): 2
- type: u64
- size: 0
- is_signed: 0
- hist_data->var_refs[3]:
- flags:
- HIST_FIELD_FL_VAR_REF
- name: woken_pid
- var.idx (into tracing_map_elt.vars[]): 0
- var.hist_data: 0000000055d65ed0
- var_ref_idx (into hist_data->var_refs[]): 3
- type: pid_t
- size: 4
- is_signed: 1
- hist_data->var_refs[4]:
- flags:
- HIST_FIELD_FL_VAR_REF
- name: next_comm
- var.idx (into tracing_map_elt.vars[]): 2
- var.hist_data: 0000000055d65ed0
- var_ref_idx (into hist_data->var_refs[]): 4
- type: char[16]
- size: 256
- is_signed: 0
- field variables:
- hist_data->field_vars[0]:
- field_vars[0].var:
- flags:
- HIST_FIELD_FL_VAR
- var.name: next_comm
- var.idx (into tracing_map_elt.vars[]): 2
- field_vars[0].val:
- ftrace_event_field name: next_comm
- type: char[16]
- size: 256
- is_signed: 0
- action tracking variables (for onmax()/onchange()/onmatch()):
- hist_data->actions[0].match_data.event_system: sched
- hist_data->actions[0].match_data.event: sched_waking
- The commands below can be used to clean things up for the next test::
- # echo '!hist:keys=next_pid:woken_pid=$waking_pid:wakeup_lat=common_timestamp.usecs-$ts0:onmatch(sched.sched_waking).wakeup_latency($wakeup_lat,$woken_pid,next_comm)' >> events/sched/sched_switch/trigger
- # echo '!hist:keys=pid:ts0=common_timestamp.usecs' >> events/sched/sched_waking/trigger
- # echo '!wakeup_latency u64 lat; pid_t pid; char comm[16]' >> synthetic_events
|