perf/core improvements and fixes:

. Add missing 'finished_round' event forwarding in 'perf inject', from Adrian Hunter.
 
 . Assorted tidy ups, from Adrian Hunter.
 
 . Fall back to sysfs event names when parsing fails, from Andi Kleen.
 
 . List pmu events in perf list, from Andi Kleen.
 
 . Cleanup some memory allocation/freeing uses, from David Ahern.
 
 . Add option to collapse undesired parts of call graph, from Greg Price.
 
 . Prep work for multi perf data file storage, from Jiri Olsa.
 
 . Add support for more than two files comparision in 'perf diff', from Jiri Olsa
 
 . A few more 'perf test' improvements, from Jiri Olsa
 
 . libtraceevent cleanups, from Namhyung Kim.
 
 . Remove odd build stall in 'perf sched' by moving a large struct initialization
   from a local variable to a global one, from Namhyung Kim.
 
 . Add support for callchains in the gtk UI, from Namhyung Kim.
 
 . Do not apply symfs for an absolute vmlinux path, fix from Namhyung Kim.
 
 . Use default include path notation for libtraceevent, from Robert Richter.
 
 . Fix 'make tools/perf', from Robert Richter.
 
 . Make Power7 events available, from Runzhen Wang.
 
 . Add --objdump option to 'perf top', from Sukadev Bhattiprolu.
 
 Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.13 (GNU/Linux)
 
 iQIcBAABAgAGBQJR6EOuAAoJENZQFvNTUqpAqjEP/1Ist/eR9be8YhljMz8Yxl1o
 JXktgxSkMS/n59lRibUuGZrgPKPNxivK6AEbnbZxzZoHDBS8tnAAOXUuUVTtNCoT
 YsQurQjCmyXHIvYqwMaYarrhoIv33LdJyshskW3GZ81UfeeC6QoC56he3VTg1dEd
 k8snS4F8LJpBQizRJN6s959nF+pyw16wqiGYKJ80G1nhPTsStz8NSSWdCRVbyXl9
 fG0S/lLvUfilGT/ixHcvS62ENHiErL4N6jGNV4XeQqoADhrQvCwziDr+BORfJB9K
 udbO0PFS5uR4HOGNqZOPZfPxW8cTUXV9cCscLScKEVUghKz9rzHbPTTSDejXna/h
 cqLjRW1xpWUmIRY7Y5zSoBJIsh2t3vo4TkZoRNZxhCexoOT/qIUL6bWVZoxqaKzG
 xwL4DopOvb/DdUDkb+UB9+9kW4rDoMR1wUb6XXuGx8EqM8LHiA3TAPcGwmNh/IM6
 4maUhgyOFad3rm5mcjO7IoCU7NxoWR1dKsjGYteZeZv17X30UfRFwIIH+8l2Ma4o
 bpBQ4DKu07jXRUZXcUajOhj7cZO+UmE6c4YoAPpv+CQ1YKVH4/YHYf6RBWdjGLqV
 kqOrQuSopVztmaglrh93e+cYkfvNjZAC2EOzhx+UxcPqh9zh1Pil8LE1DwjChW5m
 /Y/NPH98nDvXY3N4vlLK
 =xk/v
 -----END PGP SIGNATURE-----

Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core

Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:

 * Add missing 'finished_round' event forwarding in 'perf inject', from Adrian Hunter.

 * Assorted tidy ups, from Adrian Hunter.

 * Fall back to sysfs event names when parsing fails, from Andi Kleen.

 * List pmu events in perf list, from Andi Kleen.

 * Cleanup some memory allocation/freeing uses, from David Ahern.

 * Add option to collapse undesired parts of call graph, from Greg Price.

 * Prep work for multi perf data file storage, from Jiri Olsa.

 * Add support for more than two files comparision in 'perf diff', from Jiri Olsa

 * A few more 'perf test' improvements, from Jiri Olsa

 * libtraceevent cleanups, from Namhyung Kim.

 * Remove odd build stall in 'perf sched' by moving a large struct initialization
   from a local variable to a global one, from Namhyung Kim.

 * Add support for callchains in the gtk UI, from Namhyung Kim.

 * Do not apply symfs for an absolute vmlinux path, fix from Namhyung Kim.

 * Use default include path notation for libtraceevent, from Robert Richter.

 * Fix 'make tools/perf', from Robert Richter.

 * Make Power7 events available, from Runzhen Wang.

 * Add --objdump option to 'perf top', from Sukadev Bhattiprolu.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
Ingo Molnar 2013-07-19 09:35:30 +02:00
commit 5a9821321e
68 changed files with 2952 additions and 1212 deletions

View File

@ -142,11 +142,11 @@ extern ssize_t power_events_sysfs_show(struct device *dev,
#define EVENT_PTR(_id, _suffix) &EVENT_VAR(_id, _suffix).attr.attr
#define EVENT_ATTR(_name, _id, _suffix) \
PMU_EVENT_ATTR(_name, EVENT_VAR(_id, _suffix), PME_PM_##_id, \
PMU_EVENT_ATTR(_name, EVENT_VAR(_id, _suffix), PME_##_id, \
power_events_sysfs_show)
#define GENERIC_EVENT_ATTR(_name, _id) EVENT_ATTR(_name, _id, _g)
#define GENERIC_EVENT_PTR(_id) EVENT_PTR(_id, _g)
#define POWER_EVENT_ATTR(_name, _id) EVENT_ATTR(PM_##_name, _id, _p)
#define POWER_EVENT_ATTR(_name, _id) EVENT_ATTR(_name, _id, _p)
#define POWER_EVENT_PTR(_id) EVENT_PTR(_id, _p)

View File

@ -0,0 +1,548 @@
/*
* Performance counter support for POWER7 processors.
*
* Copyright 2013 Runzhen Wang, IBM Corporation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
EVENT(PM_IC_DEMAND_L2_BR_ALL, 0x04898)
EVENT(PM_GCT_UTIL_7_TO_10_SLOTS, 0x020a0)
EVENT(PM_PMC2_SAVED, 0x10022)
EVENT(PM_CMPLU_STALL_DFU, 0x2003c)
EVENT(PM_VSU0_16FLOP, 0x0a0a4)
EVENT(PM_MRK_LSU_DERAT_MISS, 0x3d05a)
EVENT(PM_MRK_ST_CMPL, 0x10034)
EVENT(PM_NEST_PAIR3_ADD, 0x40881)
EVENT(PM_L2_ST_DISP, 0x46180)
EVENT(PM_L2_CASTOUT_MOD, 0x16180)
EVENT(PM_ISEG, 0x020a4)
EVENT(PM_MRK_INST_TIMEO, 0x40034)
EVENT(PM_L2_RCST_DISP_FAIL_ADDR, 0x36282)
EVENT(PM_LSU1_DC_PREF_STREAM_CONFIRM, 0x0d0b6)
EVENT(PM_IERAT_WR_64K, 0x040be)
EVENT(PM_MRK_DTLB_MISS_16M, 0x4d05e)
EVENT(PM_IERAT_MISS, 0x100f6)
EVENT(PM_MRK_PTEG_FROM_LMEM, 0x4d052)
EVENT(PM_FLOP, 0x100f4)
EVENT(PM_THRD_PRIO_4_5_CYC, 0x040b4)
EVENT(PM_BR_PRED_TA, 0x040aa)
EVENT(PM_CMPLU_STALL_FXU, 0x20014)
EVENT(PM_EXT_INT, 0x200f8)
EVENT(PM_VSU_FSQRT_FDIV, 0x0a888)
EVENT(PM_MRK_LD_MISS_EXPOSED_CYC, 0x1003e)
EVENT(PM_LSU1_LDF, 0x0c086)
EVENT(PM_IC_WRITE_ALL, 0x0488c)
EVENT(PM_LSU0_SRQ_STFWD, 0x0c0a0)
EVENT(PM_PTEG_FROM_RL2L3_MOD, 0x1c052)
EVENT(PM_MRK_DATA_FROM_L31_SHR, 0x1d04e)
EVENT(PM_DATA_FROM_L21_MOD, 0x3c046)
EVENT(PM_VSU1_SCAL_DOUBLE_ISSUED, 0x0b08a)
EVENT(PM_VSU0_8FLOP, 0x0a0a0)
EVENT(PM_POWER_EVENT1, 0x1006e)
EVENT(PM_DISP_CLB_HELD_BAL, 0x02092)
EVENT(PM_VSU1_2FLOP, 0x0a09a)
EVENT(PM_LWSYNC_HELD, 0x0209a)
EVENT(PM_PTEG_FROM_DL2L3_SHR, 0x3c054)
EVENT(PM_INST_FROM_L21_MOD, 0x34046)
EVENT(PM_IERAT_XLATE_WR_16MPLUS, 0x040bc)
EVENT(PM_IC_REQ_ALL, 0x04888)
EVENT(PM_DSLB_MISS, 0x0d090)
EVENT(PM_L3_MISS, 0x1f082)
EVENT(PM_LSU0_L1_PREF, 0x0d0b8)
EVENT(PM_VSU_SCALAR_SINGLE_ISSUED, 0x0b884)
EVENT(PM_LSU1_DC_PREF_STREAM_CONFIRM_STRIDE, 0x0d0be)
EVENT(PM_L2_INST, 0x36080)
EVENT(PM_VSU0_FRSP, 0x0a0b4)
EVENT(PM_FLUSH_DISP, 0x02082)
EVENT(PM_PTEG_FROM_L2MISS, 0x4c058)
EVENT(PM_VSU1_DQ_ISSUED, 0x0b09a)
EVENT(PM_CMPLU_STALL_LSU, 0x20012)
EVENT(PM_MRK_DATA_FROM_DMEM, 0x1d04a)
EVENT(PM_LSU_FLUSH_ULD, 0x0c8b0)
EVENT(PM_PTEG_FROM_LMEM, 0x4c052)
EVENT(PM_MRK_DERAT_MISS_16M, 0x3d05c)
EVENT(PM_THRD_ALL_RUN_CYC, 0x2000c)
EVENT(PM_MEM0_PREFETCH_DISP, 0x20083)
EVENT(PM_MRK_STALL_CMPLU_CYC_COUNT, 0x3003f)
EVENT(PM_DATA_FROM_DL2L3_MOD, 0x3c04c)
EVENT(PM_VSU_FRSP, 0x0a8b4)
EVENT(PM_MRK_DATA_FROM_L21_MOD, 0x3d046)
EVENT(PM_PMC1_OVERFLOW, 0x20010)
EVENT(PM_VSU0_SINGLE, 0x0a0a8)
EVENT(PM_MRK_PTEG_FROM_L3MISS, 0x2d058)
EVENT(PM_MRK_PTEG_FROM_L31_SHR, 0x2d056)
EVENT(PM_VSU0_VECTOR_SP_ISSUED, 0x0b090)
EVENT(PM_VSU1_FEST, 0x0a0ba)
EVENT(PM_MRK_INST_DISP, 0x20030)
EVENT(PM_VSU0_COMPLEX_ISSUED, 0x0b096)
EVENT(PM_LSU1_FLUSH_UST, 0x0c0b6)
EVENT(PM_INST_CMPL, 0x00002)
EVENT(PM_FXU_IDLE, 0x1000e)
EVENT(PM_LSU0_FLUSH_ULD, 0x0c0b0)
EVENT(PM_MRK_DATA_FROM_DL2L3_MOD, 0x3d04c)
EVENT(PM_LSU_LMQ_SRQ_EMPTY_ALL_CYC, 0x3001c)
EVENT(PM_LSU1_REJECT_LMQ_FULL, 0x0c0a6)
EVENT(PM_INST_PTEG_FROM_L21_MOD, 0x3e056)
EVENT(PM_INST_FROM_RL2L3_MOD, 0x14042)
EVENT(PM_SHL_CREATED, 0x05082)
EVENT(PM_L2_ST_HIT, 0x46182)
EVENT(PM_DATA_FROM_DMEM, 0x1c04a)
EVENT(PM_L3_LD_MISS, 0x2f082)
EVENT(PM_FXU1_BUSY_FXU0_IDLE, 0x4000e)
EVENT(PM_DISP_CLB_HELD_RES, 0x02094)
EVENT(PM_L2_SN_SX_I_DONE, 0x36382)
EVENT(PM_GRP_CMPL, 0x30004)
EVENT(PM_STCX_CMPL, 0x0c098)
EVENT(PM_VSU0_2FLOP, 0x0a098)
EVENT(PM_L3_PREF_MISS, 0x3f082)
EVENT(PM_LSU_SRQ_SYNC_CYC, 0x0d096)
EVENT(PM_LSU_REJECT_ERAT_MISS, 0x20064)
EVENT(PM_L1_ICACHE_MISS, 0x200fc)
EVENT(PM_LSU1_FLUSH_SRQ, 0x0c0be)
EVENT(PM_LD_REF_L1_LSU0, 0x0c080)
EVENT(PM_VSU0_FEST, 0x0a0b8)
EVENT(PM_VSU_VECTOR_SINGLE_ISSUED, 0x0b890)
EVENT(PM_FREQ_UP, 0x4000c)
EVENT(PM_DATA_FROM_LMEM, 0x3c04a)
EVENT(PM_LSU1_LDX, 0x0c08a)
EVENT(PM_PMC3_OVERFLOW, 0x40010)
EVENT(PM_MRK_BR_MPRED, 0x30036)
EVENT(PM_SHL_MATCH, 0x05086)
EVENT(PM_MRK_BR_TAKEN, 0x10036)
EVENT(PM_CMPLU_STALL_BRU, 0x4004e)
EVENT(PM_ISLB_MISS, 0x0d092)
EVENT(PM_CYC, 0x0001e)
EVENT(PM_DISP_HELD_THERMAL, 0x30006)
EVENT(PM_INST_PTEG_FROM_RL2L3_SHR, 0x2e054)
EVENT(PM_LSU1_SRQ_STFWD, 0x0c0a2)
EVENT(PM_GCT_NOSLOT_BR_MPRED, 0x4001a)
EVENT(PM_1PLUS_PPC_CMPL, 0x100f2)
EVENT(PM_PTEG_FROM_DMEM, 0x2c052)
EVENT(PM_VSU_2FLOP, 0x0a898)
EVENT(PM_GCT_FULL_CYC, 0x04086)
EVENT(PM_MRK_DATA_FROM_L3_CYC, 0x40020)
EVENT(PM_LSU_SRQ_S0_ALLOC, 0x0d09d)
EVENT(PM_MRK_DERAT_MISS_4K, 0x1d05c)
EVENT(PM_BR_MPRED_TA, 0x040ae)
EVENT(PM_INST_PTEG_FROM_L2MISS, 0x4e058)
EVENT(PM_DPU_HELD_POWER, 0x20006)
EVENT(PM_RUN_INST_CMPL, 0x400fa)
EVENT(PM_MRK_VSU_FIN, 0x30032)
EVENT(PM_LSU_SRQ_S0_VALID, 0x0d09c)
EVENT(PM_GCT_EMPTY_CYC, 0x20008)
EVENT(PM_IOPS_DISP, 0x30014)
EVENT(PM_RUN_SPURR, 0x10008)
EVENT(PM_PTEG_FROM_L21_MOD, 0x3c056)
EVENT(PM_VSU0_1FLOP, 0x0a080)
EVENT(PM_SNOOP_TLBIE, 0x0d0b2)
EVENT(PM_DATA_FROM_L3MISS, 0x2c048)
EVENT(PM_VSU_SINGLE, 0x0a8a8)
EVENT(PM_DTLB_MISS_16G, 0x1c05e)
EVENT(PM_CMPLU_STALL_VECTOR, 0x2001c)
EVENT(PM_FLUSH, 0x400f8)
EVENT(PM_L2_LD_HIT, 0x36182)
EVENT(PM_NEST_PAIR2_AND, 0x30883)
EVENT(PM_VSU1_1FLOP, 0x0a082)
EVENT(PM_IC_PREF_REQ, 0x0408a)
EVENT(PM_L3_LD_HIT, 0x2f080)
EVENT(PM_GCT_NOSLOT_IC_MISS, 0x2001a)
EVENT(PM_DISP_HELD, 0x10006)
EVENT(PM_L2_LD, 0x16080)
EVENT(PM_LSU_FLUSH_SRQ, 0x0c8bc)
EVENT(PM_BC_PLUS_8_CONV, 0x040b8)
EVENT(PM_MRK_DATA_FROM_L31_MOD_CYC, 0x40026)
EVENT(PM_CMPLU_STALL_VECTOR_LONG, 0x4004a)
EVENT(PM_L2_RCST_BUSY_RC_FULL, 0x26282)
EVENT(PM_TB_BIT_TRANS, 0x300f8)
EVENT(PM_THERMAL_MAX, 0x40006)
EVENT(PM_LSU1_FLUSH_ULD, 0x0c0b2)
EVENT(PM_LSU1_REJECT_LHS, 0x0c0ae)
EVENT(PM_LSU_LRQ_S0_ALLOC, 0x0d09f)
EVENT(PM_L3_CO_L31, 0x4f080)
EVENT(PM_POWER_EVENT4, 0x4006e)
EVENT(PM_DATA_FROM_L31_SHR, 0x1c04e)
EVENT(PM_BR_UNCOND, 0x0409e)
EVENT(PM_LSU1_DC_PREF_STREAM_ALLOC, 0x0d0aa)
EVENT(PM_PMC4_REWIND, 0x10020)
EVENT(PM_L2_RCLD_DISP, 0x16280)
EVENT(PM_THRD_PRIO_2_3_CYC, 0x040b2)
EVENT(PM_MRK_PTEG_FROM_L2MISS, 0x4d058)
EVENT(PM_IC_DEMAND_L2_BHT_REDIRECT, 0x04098)
EVENT(PM_LSU_DERAT_MISS, 0x200f6)
EVENT(PM_IC_PREF_CANCEL_L2, 0x04094)
EVENT(PM_MRK_FIN_STALL_CYC_COUNT, 0x1003d)
EVENT(PM_BR_PRED_CCACHE, 0x040a0)
EVENT(PM_GCT_UTIL_1_TO_2_SLOTS, 0x0209c)
EVENT(PM_MRK_ST_CMPL_INT, 0x30034)
EVENT(PM_LSU_TWO_TABLEWALK_CYC, 0x0d0a6)
EVENT(PM_MRK_DATA_FROM_L3MISS, 0x2d048)
EVENT(PM_GCT_NOSLOT_CYC, 0x100f8)
EVENT(PM_LSU_SET_MPRED, 0x0c0a8)
EVENT(PM_FLUSH_DISP_TLBIE, 0x0208a)
EVENT(PM_VSU1_FCONV, 0x0a0b2)
EVENT(PM_DERAT_MISS_16G, 0x4c05c)
EVENT(PM_INST_FROM_LMEM, 0x3404a)
EVENT(PM_IC_DEMAND_L2_BR_REDIRECT, 0x0409a)
EVENT(PM_CMPLU_STALL_SCALAR_LONG, 0x20018)
EVENT(PM_INST_PTEG_FROM_L2, 0x1e050)
EVENT(PM_PTEG_FROM_L2, 0x1c050)
EVENT(PM_MRK_DATA_FROM_L21_SHR_CYC, 0x20024)
EVENT(PM_MRK_DTLB_MISS_4K, 0x2d05a)
EVENT(PM_VSU0_FPSCR, 0x0b09c)
EVENT(PM_VSU1_VECT_DOUBLE_ISSUED, 0x0b082)
EVENT(PM_MRK_PTEG_FROM_RL2L3_MOD, 0x1d052)
EVENT(PM_MEM0_RQ_DISP, 0x10083)
EVENT(PM_L2_LD_MISS, 0x26080)
EVENT(PM_VMX_RESULT_SAT_1, 0x0b0a0)
EVENT(PM_L1_PREF, 0x0d8b8)
EVENT(PM_MRK_DATA_FROM_LMEM_CYC, 0x2002c)
EVENT(PM_GRP_IC_MISS_NONSPEC, 0x1000c)
EVENT(PM_PB_NODE_PUMP, 0x10081)
EVENT(PM_SHL_MERGED, 0x05084)
EVENT(PM_NEST_PAIR1_ADD, 0x20881)
EVENT(PM_DATA_FROM_L3, 0x1c048)
EVENT(PM_LSU_FLUSH, 0x0208e)
EVENT(PM_LSU_SRQ_SYNC_COUNT, 0x0d097)
EVENT(PM_PMC2_OVERFLOW, 0x30010)
EVENT(PM_LSU_LDF, 0x0c884)
EVENT(PM_POWER_EVENT3, 0x3006e)
EVENT(PM_DISP_WT, 0x30008)
EVENT(PM_CMPLU_STALL_REJECT, 0x40016)
EVENT(PM_IC_BANK_CONFLICT, 0x04082)
EVENT(PM_BR_MPRED_CR_TA, 0x048ae)
EVENT(PM_L2_INST_MISS, 0x36082)
EVENT(PM_CMPLU_STALL_ERAT_MISS, 0x40018)
EVENT(PM_NEST_PAIR2_ADD, 0x30881)
EVENT(PM_MRK_LSU_FLUSH, 0x0d08c)
EVENT(PM_L2_LDST, 0x16880)
EVENT(PM_INST_FROM_L31_SHR, 0x1404e)
EVENT(PM_VSU0_FIN, 0x0a0bc)
EVENT(PM_LARX_LSU, 0x0c894)
EVENT(PM_INST_FROM_RMEM, 0x34042)
EVENT(PM_DISP_CLB_HELD_TLBIE, 0x02096)
EVENT(PM_MRK_DATA_FROM_DMEM_CYC, 0x2002e)
EVENT(PM_BR_PRED_CR, 0x040a8)
EVENT(PM_LSU_REJECT, 0x10064)
EVENT(PM_GCT_UTIL_3_TO_6_SLOTS, 0x0209e)
EVENT(PM_CMPLU_STALL_END_GCT_NOSLOT, 0x10028)
EVENT(PM_LSU0_REJECT_LMQ_FULL, 0x0c0a4)
EVENT(PM_VSU_FEST, 0x0a8b8)
EVENT(PM_NEST_PAIR0_AND, 0x10883)
EVENT(PM_PTEG_FROM_L3, 0x2c050)
EVENT(PM_POWER_EVENT2, 0x2006e)
EVENT(PM_IC_PREF_CANCEL_PAGE, 0x04090)
EVENT(PM_VSU0_FSQRT_FDIV, 0x0a088)
EVENT(PM_MRK_GRP_CMPL, 0x40030)
EVENT(PM_VSU0_SCAL_DOUBLE_ISSUED, 0x0b088)
EVENT(PM_GRP_DISP, 0x3000a)
EVENT(PM_LSU0_LDX, 0x0c088)
EVENT(PM_DATA_FROM_L2, 0x1c040)
EVENT(PM_MRK_DATA_FROM_RL2L3_MOD, 0x1d042)
EVENT(PM_LD_REF_L1, 0x0c880)
EVENT(PM_VSU0_VECT_DOUBLE_ISSUED, 0x0b080)
EVENT(PM_VSU1_2FLOP_DOUBLE, 0x0a08e)
EVENT(PM_THRD_PRIO_6_7_CYC, 0x040b6)
EVENT(PM_BC_PLUS_8_RSLV_TAKEN, 0x040ba)
EVENT(PM_BR_MPRED_CR, 0x040ac)
EVENT(PM_L3_CO_MEM, 0x4f082)
EVENT(PM_LD_MISS_L1, 0x400f0)
EVENT(PM_DATA_FROM_RL2L3_MOD, 0x1c042)
EVENT(PM_LSU_SRQ_FULL_CYC, 0x1001a)
EVENT(PM_TABLEWALK_CYC, 0x10026)
EVENT(PM_MRK_PTEG_FROM_RMEM, 0x3d052)
EVENT(PM_LSU_SRQ_STFWD, 0x0c8a0)
EVENT(PM_INST_PTEG_FROM_RMEM, 0x3e052)
EVENT(PM_FXU0_FIN, 0x10004)
EVENT(PM_LSU1_L1_SW_PREF, 0x0c09e)
EVENT(PM_PTEG_FROM_L31_MOD, 0x1c054)
EVENT(PM_PMC5_OVERFLOW, 0x10024)
EVENT(PM_LD_REF_L1_LSU1, 0x0c082)
EVENT(PM_INST_PTEG_FROM_L21_SHR, 0x4e056)
EVENT(PM_CMPLU_STALL_THRD, 0x1001c)
EVENT(PM_DATA_FROM_RMEM, 0x3c042)
EVENT(PM_VSU0_SCAL_SINGLE_ISSUED, 0x0b084)
EVENT(PM_BR_MPRED_LSTACK, 0x040a6)
EVENT(PM_MRK_DATA_FROM_RL2L3_MOD_CYC, 0x40028)
EVENT(PM_LSU0_FLUSH_UST, 0x0c0b4)
EVENT(PM_LSU_NCST, 0x0c090)
EVENT(PM_BR_TAKEN, 0x20004)
EVENT(PM_INST_PTEG_FROM_LMEM, 0x4e052)
EVENT(PM_GCT_NOSLOT_BR_MPRED_IC_MISS, 0x4001c)
EVENT(PM_DTLB_MISS_4K, 0x2c05a)
EVENT(PM_PMC4_SAVED, 0x30022)
EVENT(PM_VSU1_PERMUTE_ISSUED, 0x0b092)
EVENT(PM_SLB_MISS, 0x0d890)
EVENT(PM_LSU1_FLUSH_LRQ, 0x0c0ba)
EVENT(PM_DTLB_MISS, 0x300fc)
EVENT(PM_VSU1_FRSP, 0x0a0b6)
EVENT(PM_VSU_VECTOR_DOUBLE_ISSUED, 0x0b880)
EVENT(PM_L2_CASTOUT_SHR, 0x16182)
EVENT(PM_DATA_FROM_DL2L3_SHR, 0x3c044)
EVENT(PM_VSU1_STF, 0x0b08e)
EVENT(PM_ST_FIN, 0x200f0)
EVENT(PM_PTEG_FROM_L21_SHR, 0x4c056)
EVENT(PM_L2_LOC_GUESS_WRONG, 0x26480)
EVENT(PM_MRK_STCX_FAIL, 0x0d08e)
EVENT(PM_LSU0_REJECT_LHS, 0x0c0ac)
EVENT(PM_IC_PREF_CANCEL_HIT, 0x04092)
EVENT(PM_L3_PREF_BUSY, 0x4f080)
EVENT(PM_MRK_BRU_FIN, 0x2003a)
EVENT(PM_LSU1_NCLD, 0x0c08e)
EVENT(PM_INST_PTEG_FROM_L31_MOD, 0x1e054)
EVENT(PM_LSU_NCLD, 0x0c88c)
EVENT(PM_LSU_LDX, 0x0c888)
EVENT(PM_L2_LOC_GUESS_CORRECT, 0x16480)
EVENT(PM_THRESH_TIMEO, 0x10038)
EVENT(PM_L3_PREF_ST, 0x0d0ae)
EVENT(PM_DISP_CLB_HELD_SYNC, 0x02098)
EVENT(PM_VSU_SIMPLE_ISSUED, 0x0b894)
EVENT(PM_VSU1_SINGLE, 0x0a0aa)
EVENT(PM_DATA_TABLEWALK_CYC, 0x3001a)
EVENT(PM_L2_RC_ST_DONE, 0x36380)
EVENT(PM_MRK_PTEG_FROM_L21_MOD, 0x3d056)
EVENT(PM_LARX_LSU1, 0x0c096)
EVENT(PM_MRK_DATA_FROM_RMEM, 0x3d042)
EVENT(PM_DISP_CLB_HELD, 0x02090)
EVENT(PM_DERAT_MISS_4K, 0x1c05c)
EVENT(PM_L2_RCLD_DISP_FAIL_ADDR, 0x16282)
EVENT(PM_SEG_EXCEPTION, 0x028a4)
EVENT(PM_FLUSH_DISP_SB, 0x0208c)
EVENT(PM_L2_DC_INV, 0x26182)
EVENT(PM_PTEG_FROM_DL2L3_MOD, 0x4c054)
EVENT(PM_DSEG, 0x020a6)
EVENT(PM_BR_PRED_LSTACK, 0x040a2)
EVENT(PM_VSU0_STF, 0x0b08c)
EVENT(PM_LSU_FX_FIN, 0x10066)
EVENT(PM_DERAT_MISS_16M, 0x3c05c)
EVENT(PM_MRK_PTEG_FROM_DL2L3_MOD, 0x4d054)
EVENT(PM_GCT_UTIL_11_PLUS_SLOTS, 0x020a2)
EVENT(PM_INST_FROM_L3, 0x14048)
EVENT(PM_MRK_IFU_FIN, 0x3003a)
EVENT(PM_ITLB_MISS, 0x400fc)
EVENT(PM_VSU_STF, 0x0b88c)
EVENT(PM_LSU_FLUSH_UST, 0x0c8b4)
EVENT(PM_L2_LDST_MISS, 0x26880)
EVENT(PM_FXU1_FIN, 0x40004)
EVENT(PM_SHL_DEALLOCATED, 0x05080)
EVENT(PM_L2_SN_M_WR_DONE, 0x46382)
EVENT(PM_LSU_REJECT_SET_MPRED, 0x0c8a8)
EVENT(PM_L3_PREF_LD, 0x0d0ac)
EVENT(PM_L2_SN_M_RD_DONE, 0x46380)
EVENT(PM_MRK_DERAT_MISS_16G, 0x4d05c)
EVENT(PM_VSU_FCONV, 0x0a8b0)
EVENT(PM_ANY_THRD_RUN_CYC, 0x100fa)
EVENT(PM_LSU_LMQ_FULL_CYC, 0x0d0a4)
EVENT(PM_MRK_LSU_REJECT_LHS, 0x0d082)
EVENT(PM_MRK_LD_MISS_L1_CYC, 0x4003e)
EVENT(PM_MRK_DATA_FROM_L2_CYC, 0x20020)
EVENT(PM_INST_IMC_MATCH_DISP, 0x30016)
EVENT(PM_MRK_DATA_FROM_RMEM_CYC, 0x4002c)
EVENT(PM_VSU0_SIMPLE_ISSUED, 0x0b094)
EVENT(PM_CMPLU_STALL_DIV, 0x40014)
EVENT(PM_MRK_PTEG_FROM_RL2L3_SHR, 0x2d054)
EVENT(PM_VSU_FMA_DOUBLE, 0x0a890)
EVENT(PM_VSU_4FLOP, 0x0a89c)
EVENT(PM_VSU1_FIN, 0x0a0be)
EVENT(PM_NEST_PAIR1_AND, 0x20883)
EVENT(PM_INST_PTEG_FROM_RL2L3_MOD, 0x1e052)
EVENT(PM_RUN_CYC, 0x200f4)
EVENT(PM_PTEG_FROM_RMEM, 0x3c052)
EVENT(PM_LSU_LRQ_S0_VALID, 0x0d09e)
EVENT(PM_LSU0_LDF, 0x0c084)
EVENT(PM_FLUSH_COMPLETION, 0x30012)
EVENT(PM_ST_MISS_L1, 0x300f0)
EVENT(PM_L2_NODE_PUMP, 0x36480)
EVENT(PM_INST_FROM_DL2L3_SHR, 0x34044)
EVENT(PM_MRK_STALL_CMPLU_CYC, 0x3003e)
EVENT(PM_VSU1_DENORM, 0x0a0ae)
EVENT(PM_MRK_DATA_FROM_L31_SHR_CYC, 0x20026)
EVENT(PM_NEST_PAIR0_ADD, 0x10881)
EVENT(PM_INST_FROM_L3MISS, 0x24048)
EVENT(PM_EE_OFF_EXT_INT, 0x02080)
EVENT(PM_INST_PTEG_FROM_DMEM, 0x2e052)
EVENT(PM_INST_FROM_DL2L3_MOD, 0x3404c)
EVENT(PM_PMC6_OVERFLOW, 0x30024)
EVENT(PM_VSU_2FLOP_DOUBLE, 0x0a88c)
EVENT(PM_TLB_MISS, 0x20066)
EVENT(PM_FXU_BUSY, 0x2000e)
EVENT(PM_L2_RCLD_DISP_FAIL_OTHER, 0x26280)
EVENT(PM_LSU_REJECT_LMQ_FULL, 0x0c8a4)
EVENT(PM_IC_RELOAD_SHR, 0x04096)
EVENT(PM_GRP_MRK, 0x10031)
EVENT(PM_MRK_ST_NEST, 0x20034)
EVENT(PM_VSU1_FSQRT_FDIV, 0x0a08a)
EVENT(PM_LSU0_FLUSH_LRQ, 0x0c0b8)
EVENT(PM_LARX_LSU0, 0x0c094)
EVENT(PM_IBUF_FULL_CYC, 0x04084)
EVENT(PM_MRK_DATA_FROM_DL2L3_SHR_CYC, 0x2002a)
EVENT(PM_LSU_DC_PREF_STREAM_ALLOC, 0x0d8a8)
EVENT(PM_GRP_MRK_CYC, 0x10030)
EVENT(PM_MRK_DATA_FROM_RL2L3_SHR_CYC, 0x20028)
EVENT(PM_L2_GLOB_GUESS_CORRECT, 0x16482)
EVENT(PM_LSU_REJECT_LHS, 0x0c8ac)
EVENT(PM_MRK_DATA_FROM_LMEM, 0x3d04a)
EVENT(PM_INST_PTEG_FROM_L3, 0x2e050)
EVENT(PM_FREQ_DOWN, 0x3000c)
EVENT(PM_PB_RETRY_NODE_PUMP, 0x30081)
EVENT(PM_INST_FROM_RL2L3_SHR, 0x1404c)
EVENT(PM_MRK_INST_ISSUED, 0x10032)
EVENT(PM_PTEG_FROM_L3MISS, 0x2c058)
EVENT(PM_RUN_PURR, 0x400f4)
EVENT(PM_MRK_GRP_IC_MISS, 0x40038)
EVENT(PM_MRK_DATA_FROM_L3, 0x1d048)
EVENT(PM_CMPLU_STALL_DCACHE_MISS, 0x20016)
EVENT(PM_PTEG_FROM_RL2L3_SHR, 0x2c054)
EVENT(PM_LSU_FLUSH_LRQ, 0x0c8b8)
EVENT(PM_MRK_DERAT_MISS_64K, 0x2d05c)
EVENT(PM_INST_PTEG_FROM_DL2L3_MOD, 0x4e054)
EVENT(PM_L2_ST_MISS, 0x26082)
EVENT(PM_MRK_PTEG_FROM_L21_SHR, 0x4d056)
EVENT(PM_LWSYNC, 0x0d094)
EVENT(PM_LSU0_DC_PREF_STREAM_CONFIRM_STRIDE, 0x0d0bc)
EVENT(PM_MRK_LSU_FLUSH_LRQ, 0x0d088)
EVENT(PM_INST_IMC_MATCH_CMPL, 0x100f0)
EVENT(PM_NEST_PAIR3_AND, 0x40883)
EVENT(PM_PB_RETRY_SYS_PUMP, 0x40081)
EVENT(PM_MRK_INST_FIN, 0x30030)
EVENT(PM_MRK_PTEG_FROM_DL2L3_SHR, 0x3d054)
EVENT(PM_INST_FROM_L31_MOD, 0x14044)
EVENT(PM_MRK_DTLB_MISS_64K, 0x3d05e)
EVENT(PM_LSU_FIN, 0x30066)
EVENT(PM_MRK_LSU_REJECT, 0x40064)
EVENT(PM_L2_CO_FAIL_BUSY, 0x16382)
EVENT(PM_MEM0_WQ_DISP, 0x40083)
EVENT(PM_DATA_FROM_L31_MOD, 0x1c044)
EVENT(PM_THERMAL_WARN, 0x10016)
EVENT(PM_VSU0_4FLOP, 0x0a09c)
EVENT(PM_BR_MPRED_CCACHE, 0x040a4)
EVENT(PM_CMPLU_STALL_IFU, 0x4004c)
EVENT(PM_L1_DEMAND_WRITE, 0x0408c)
EVENT(PM_FLUSH_BR_MPRED, 0x02084)
EVENT(PM_MRK_DTLB_MISS_16G, 0x1d05e)
EVENT(PM_MRK_PTEG_FROM_DMEM, 0x2d052)
EVENT(PM_L2_RCST_DISP, 0x36280)
EVENT(PM_CMPLU_STALL, 0x4000a)
EVENT(PM_LSU_PARTIAL_CDF, 0x0c0aa)
EVENT(PM_DISP_CLB_HELD_SB, 0x020a8)
EVENT(PM_VSU0_FMA_DOUBLE, 0x0a090)
EVENT(PM_FXU0_BUSY_FXU1_IDLE, 0x3000e)
EVENT(PM_IC_DEMAND_CYC, 0x10018)
EVENT(PM_MRK_DATA_FROM_L21_SHR, 0x3d04e)
EVENT(PM_MRK_LSU_FLUSH_UST, 0x0d086)
EVENT(PM_INST_PTEG_FROM_L3MISS, 0x2e058)
EVENT(PM_VSU_DENORM, 0x0a8ac)
EVENT(PM_MRK_LSU_PARTIAL_CDF, 0x0d080)
EVENT(PM_INST_FROM_L21_SHR, 0x3404e)
EVENT(PM_IC_PREF_WRITE, 0x0408e)
EVENT(PM_BR_PRED, 0x0409c)
EVENT(PM_INST_FROM_DMEM, 0x1404a)
EVENT(PM_IC_PREF_CANCEL_ALL, 0x04890)
EVENT(PM_LSU_DC_PREF_STREAM_CONFIRM, 0x0d8b4)
EVENT(PM_MRK_LSU_FLUSH_SRQ, 0x0d08a)
EVENT(PM_MRK_FIN_STALL_CYC, 0x1003c)
EVENT(PM_L2_RCST_DISP_FAIL_OTHER, 0x46280)
EVENT(PM_VSU1_DD_ISSUED, 0x0b098)
EVENT(PM_PTEG_FROM_L31_SHR, 0x2c056)
EVENT(PM_DATA_FROM_L21_SHR, 0x3c04e)
EVENT(PM_LSU0_NCLD, 0x0c08c)
EVENT(PM_VSU1_4FLOP, 0x0a09e)
EVENT(PM_VSU1_8FLOP, 0x0a0a2)
EVENT(PM_VSU_8FLOP, 0x0a8a0)
EVENT(PM_LSU_LMQ_SRQ_EMPTY_CYC, 0x2003e)
EVENT(PM_DTLB_MISS_64K, 0x3c05e)
EVENT(PM_THRD_CONC_RUN_INST, 0x300f4)
EVENT(PM_MRK_PTEG_FROM_L2, 0x1d050)
EVENT(PM_PB_SYS_PUMP, 0x20081)
EVENT(PM_VSU_FIN, 0x0a8bc)
EVENT(PM_MRK_DATA_FROM_L31_MOD, 0x1d044)
EVENT(PM_THRD_PRIO_0_1_CYC, 0x040b0)
EVENT(PM_DERAT_MISS_64K, 0x2c05c)
EVENT(PM_PMC2_REWIND, 0x30020)
EVENT(PM_INST_FROM_L2, 0x14040)
EVENT(PM_GRP_BR_MPRED_NONSPEC, 0x1000a)
EVENT(PM_INST_DISP, 0x200f2)
EVENT(PM_MEM0_RD_CANCEL_TOTAL, 0x30083)
EVENT(PM_LSU0_DC_PREF_STREAM_CONFIRM, 0x0d0b4)
EVENT(PM_L1_DCACHE_RELOAD_VALID, 0x300f6)
EVENT(PM_VSU_SCALAR_DOUBLE_ISSUED, 0x0b888)
EVENT(PM_L3_PREF_HIT, 0x3f080)
EVENT(PM_MRK_PTEG_FROM_L31_MOD, 0x1d054)
EVENT(PM_CMPLU_STALL_STORE, 0x2004a)
EVENT(PM_MRK_FXU_FIN, 0x20038)
EVENT(PM_PMC4_OVERFLOW, 0x10010)
EVENT(PM_MRK_PTEG_FROM_L3, 0x2d050)
EVENT(PM_LSU0_LMQ_LHR_MERGE, 0x0d098)
EVENT(PM_BTAC_HIT, 0x0508a)
EVENT(PM_L3_RD_BUSY, 0x4f082)
EVENT(PM_LSU0_L1_SW_PREF, 0x0c09c)
EVENT(PM_INST_FROM_L2MISS, 0x44048)
EVENT(PM_LSU0_DC_PREF_STREAM_ALLOC, 0x0d0a8)
EVENT(PM_L2_ST, 0x16082)
EVENT(PM_VSU0_DENORM, 0x0a0ac)
EVENT(PM_MRK_DATA_FROM_DL2L3_SHR, 0x3d044)
EVENT(PM_BR_PRED_CR_TA, 0x048aa)
EVENT(PM_VSU0_FCONV, 0x0a0b0)
EVENT(PM_MRK_LSU_FLUSH_ULD, 0x0d084)
EVENT(PM_BTAC_MISS, 0x05088)
EVENT(PM_MRK_LD_MISS_EXPOSED_CYC_COUNT, 0x1003f)
EVENT(PM_MRK_DATA_FROM_L2, 0x1d040)
EVENT(PM_LSU_DCACHE_RELOAD_VALID, 0x0d0a2)
EVENT(PM_VSU_FMA, 0x0a884)
EVENT(PM_LSU0_FLUSH_SRQ, 0x0c0bc)
EVENT(PM_LSU1_L1_PREF, 0x0d0ba)
EVENT(PM_IOPS_CMPL, 0x10014)
EVENT(PM_L2_SYS_PUMP, 0x36482)
EVENT(PM_L2_RCLD_BUSY_RC_FULL, 0x46282)
EVENT(PM_LSU_LMQ_S0_ALLOC, 0x0d0a1)
EVENT(PM_FLUSH_DISP_SYNC, 0x02088)
EVENT(PM_MRK_DATA_FROM_DL2L3_MOD_CYC, 0x4002a)
EVENT(PM_L2_IC_INV, 0x26180)
EVENT(PM_MRK_DATA_FROM_L21_MOD_CYC, 0x40024)
EVENT(PM_L3_PREF_LDST, 0x0d8ac)
EVENT(PM_LSU_SRQ_EMPTY_CYC, 0x40008)
EVENT(PM_LSU_LMQ_S0_VALID, 0x0d0a0)
EVENT(PM_FLUSH_PARTIAL, 0x02086)
EVENT(PM_VSU1_FMA_DOUBLE, 0x0a092)
EVENT(PM_1PLUS_PPC_DISP, 0x400f2)
EVENT(PM_DATA_FROM_L2MISS, 0x200fe)
EVENT(PM_SUSPENDED, 0x00000)
EVENT(PM_VSU0_FMA, 0x0a084)
EVENT(PM_CMPLU_STALL_SCALAR, 0x40012)
EVENT(PM_STCX_FAIL, 0x0c09a)
EVENT(PM_VSU0_FSQRT_FDIV_DOUBLE, 0x0a094)
EVENT(PM_DC_PREF_DST, 0x0d0b0)
EVENT(PM_VSU1_SCAL_SINGLE_ISSUED, 0x0b086)
EVENT(PM_L3_HIT, 0x1f080)
EVENT(PM_L2_GLOB_GUESS_WRONG, 0x26482)
EVENT(PM_MRK_DFU_FIN, 0x20032)
EVENT(PM_INST_FROM_L1, 0x04080)
EVENT(PM_BRU_FIN, 0x10068)
EVENT(PM_IC_DEMAND_REQ, 0x04088)
EVENT(PM_VSU1_FSQRT_FDIV_DOUBLE, 0x0a096)
EVENT(PM_VSU1_FMA, 0x0a086)
EVENT(PM_MRK_LD_MISS_L1, 0x20036)
EVENT(PM_VSU0_2FLOP_DOUBLE, 0x0a08c)
EVENT(PM_LSU_DC_PREF_STRIDED_STREAM_CONFIRM, 0x0d8bc)
EVENT(PM_INST_PTEG_FROM_L31_SHR, 0x2e056)
EVENT(PM_MRK_LSU_REJECT_ERAT_MISS, 0x30064)
EVENT(PM_MRK_DATA_FROM_L2MISS, 0x4d048)
EVENT(PM_DATA_FROM_RL2L3_SHR, 0x1c04c)
EVENT(PM_INST_FROM_PREF, 0x14046)
EVENT(PM_VSU1_SQ, 0x0b09e)
EVENT(PM_L2_LD_DISP, 0x36180)
EVENT(PM_L2_DISP_ALL, 0x46080)
EVENT(PM_THRD_GRP_CMPL_BOTH_CYC, 0x10012)
EVENT(PM_VSU_FSQRT_FDIV_DOUBLE, 0x0a894)
EVENT(PM_BR_MPRED, 0x400f6)
EVENT(PM_INST_PTEG_FROM_DL2L3_SHR, 0x3e054)
EVENT(PM_VSU_1FLOP, 0x0a880)
EVENT(PM_HV_CYC, 0x2000a)
EVENT(PM_MRK_LSU_FIN, 0x40032)
EVENT(PM_MRK_DATA_FROM_RL2L3_SHR, 0x1d04c)
EVENT(PM_DTLB_MISS_16M, 0x4c05e)
EVENT(PM_LSU1_LMQ_LHR_MERGE, 0x0d09a)
EVENT(PM_IFU_FIN, 0x40066)

View File

@ -53,37 +53,13 @@
/*
* Power7 event codes.
*/
#define PME_PM_CYC 0x1e
#define PME_PM_GCT_NOSLOT_CYC 0x100f8
#define PME_PM_CMPLU_STALL 0x4000a
#define PME_PM_INST_CMPL 0x2
#define PME_PM_LD_REF_L1 0xc880
#define PME_PM_LD_MISS_L1 0x400f0
#define PME_PM_BRU_FIN 0x10068
#define PME_PM_BR_MPRED 0x400f6
#define EVENT(_name, _code) \
PME_##_name = _code,
#define PME_PM_CMPLU_STALL_FXU 0x20014
#define PME_PM_CMPLU_STALL_DIV 0x40014
#define PME_PM_CMPLU_STALL_SCALAR 0x40012
#define PME_PM_CMPLU_STALL_SCALAR_LONG 0x20018
#define PME_PM_CMPLU_STALL_VECTOR 0x2001c
#define PME_PM_CMPLU_STALL_VECTOR_LONG 0x4004a
#define PME_PM_CMPLU_STALL_LSU 0x20012
#define PME_PM_CMPLU_STALL_REJECT 0x40016
#define PME_PM_CMPLU_STALL_ERAT_MISS 0x40018
#define PME_PM_CMPLU_STALL_DCACHE_MISS 0x20016
#define PME_PM_CMPLU_STALL_STORE 0x2004a
#define PME_PM_CMPLU_STALL_THRD 0x1001c
#define PME_PM_CMPLU_STALL_IFU 0x4004c
#define PME_PM_CMPLU_STALL_BRU 0x4004e
#define PME_PM_GCT_NOSLOT_IC_MISS 0x2001a
#define PME_PM_GCT_NOSLOT_BR_MPRED 0x4001a
#define PME_PM_GCT_NOSLOT_BR_MPRED_IC_MISS 0x4001c
#define PME_PM_GRP_CMPL 0x30004
#define PME_PM_1PLUS_PPC_CMPL 0x100f2
#define PME_PM_CMPLU_STALL_DFU 0x2003c
#define PME_PM_RUN_CYC 0x200f4
#define PME_PM_RUN_INST_CMPL 0x400fa
enum {
#include "power7-events-list.h"
};
#undef EVENT
/*
* Layout of constraint bits:
@ -398,96 +374,36 @@ static int power7_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
};
GENERIC_EVENT_ATTR(cpu-cycles, CYC);
GENERIC_EVENT_ATTR(stalled-cycles-frontend, GCT_NOSLOT_CYC);
GENERIC_EVENT_ATTR(stalled-cycles-backend, CMPLU_STALL);
GENERIC_EVENT_ATTR(instructions, INST_CMPL);
GENERIC_EVENT_ATTR(cache-references, LD_REF_L1);
GENERIC_EVENT_ATTR(cache-misses, LD_MISS_L1);
GENERIC_EVENT_ATTR(branch-instructions, BRU_FIN);
GENERIC_EVENT_ATTR(branch-misses, BR_MPRED);
GENERIC_EVENT_ATTR(cpu-cycles, PM_CYC);
GENERIC_EVENT_ATTR(stalled-cycles-frontend, PM_GCT_NOSLOT_CYC);
GENERIC_EVENT_ATTR(stalled-cycles-backend, PM_CMPLU_STALL);
GENERIC_EVENT_ATTR(instructions, PM_INST_CMPL);
GENERIC_EVENT_ATTR(cache-references, PM_LD_REF_L1);
GENERIC_EVENT_ATTR(cache-misses, PM_LD_MISS_L1);
GENERIC_EVENT_ATTR(branch-instructions, PM_BRU_FIN);
GENERIC_EVENT_ATTR(branch-misses, PM_BR_MPRED);
POWER_EVENT_ATTR(CYC, CYC);
POWER_EVENT_ATTR(GCT_NOSLOT_CYC, GCT_NOSLOT_CYC);
POWER_EVENT_ATTR(CMPLU_STALL, CMPLU_STALL);
POWER_EVENT_ATTR(INST_CMPL, INST_CMPL);
POWER_EVENT_ATTR(LD_REF_L1, LD_REF_L1);
POWER_EVENT_ATTR(LD_MISS_L1, LD_MISS_L1);
POWER_EVENT_ATTR(BRU_FIN, BRU_FIN)
POWER_EVENT_ATTR(BR_MPRED, BR_MPRED);
#define EVENT(_name, _code) POWER_EVENT_ATTR(_name, _name);
#include "power7-events-list.h"
#undef EVENT
POWER_EVENT_ATTR(CMPLU_STALL_FXU, CMPLU_STALL_FXU);
POWER_EVENT_ATTR(CMPLU_STALL_DIV, CMPLU_STALL_DIV);
POWER_EVENT_ATTR(CMPLU_STALL_SCALAR, CMPLU_STALL_SCALAR);
POWER_EVENT_ATTR(CMPLU_STALL_SCALAR_LONG, CMPLU_STALL_SCALAR_LONG);
POWER_EVENT_ATTR(CMPLU_STALL_VECTOR, CMPLU_STALL_VECTOR);
POWER_EVENT_ATTR(CMPLU_STALL_VECTOR_LONG, CMPLU_STALL_VECTOR_LONG);
POWER_EVENT_ATTR(CMPLU_STALL_LSU, CMPLU_STALL_LSU);
POWER_EVENT_ATTR(CMPLU_STALL_REJECT, CMPLU_STALL_REJECT);
POWER_EVENT_ATTR(CMPLU_STALL_ERAT_MISS, CMPLU_STALL_ERAT_MISS);
POWER_EVENT_ATTR(CMPLU_STALL_DCACHE_MISS, CMPLU_STALL_DCACHE_MISS);
POWER_EVENT_ATTR(CMPLU_STALL_STORE, CMPLU_STALL_STORE);
POWER_EVENT_ATTR(CMPLU_STALL_THRD, CMPLU_STALL_THRD);
POWER_EVENT_ATTR(CMPLU_STALL_IFU, CMPLU_STALL_IFU);
POWER_EVENT_ATTR(CMPLU_STALL_BRU, CMPLU_STALL_BRU);
POWER_EVENT_ATTR(GCT_NOSLOT_IC_MISS, GCT_NOSLOT_IC_MISS);
POWER_EVENT_ATTR(GCT_NOSLOT_BR_MPRED, GCT_NOSLOT_BR_MPRED);
POWER_EVENT_ATTR(GCT_NOSLOT_BR_MPRED_IC_MISS, GCT_NOSLOT_BR_MPRED_IC_MISS);
POWER_EVENT_ATTR(GRP_CMPL, GRP_CMPL);
POWER_EVENT_ATTR(1PLUS_PPC_CMPL, 1PLUS_PPC_CMPL);
POWER_EVENT_ATTR(CMPLU_STALL_DFU, CMPLU_STALL_DFU);
POWER_EVENT_ATTR(RUN_CYC, RUN_CYC);
POWER_EVENT_ATTR(RUN_INST_CMPL, RUN_INST_CMPL);
#define EVENT(_name, _code) POWER_EVENT_PTR(_name),
static struct attribute *power7_events_attr[] = {
GENERIC_EVENT_PTR(CYC),
GENERIC_EVENT_PTR(GCT_NOSLOT_CYC),
GENERIC_EVENT_PTR(CMPLU_STALL),
GENERIC_EVENT_PTR(INST_CMPL),
GENERIC_EVENT_PTR(LD_REF_L1),
GENERIC_EVENT_PTR(LD_MISS_L1),
GENERIC_EVENT_PTR(BRU_FIN),
GENERIC_EVENT_PTR(BR_MPRED),
GENERIC_EVENT_PTR(PM_CYC),
GENERIC_EVENT_PTR(PM_GCT_NOSLOT_CYC),
GENERIC_EVENT_PTR(PM_CMPLU_STALL),
GENERIC_EVENT_PTR(PM_INST_CMPL),
GENERIC_EVENT_PTR(PM_LD_REF_L1),
GENERIC_EVENT_PTR(PM_LD_MISS_L1),
GENERIC_EVENT_PTR(PM_BRU_FIN),
GENERIC_EVENT_PTR(PM_BR_MPRED),
POWER_EVENT_PTR(CYC),
POWER_EVENT_PTR(GCT_NOSLOT_CYC),
POWER_EVENT_PTR(CMPLU_STALL),
POWER_EVENT_PTR(INST_CMPL),
POWER_EVENT_PTR(LD_REF_L1),
POWER_EVENT_PTR(LD_MISS_L1),
POWER_EVENT_PTR(BRU_FIN),
POWER_EVENT_PTR(BR_MPRED),
POWER_EVENT_PTR(CMPLU_STALL_FXU),
POWER_EVENT_PTR(CMPLU_STALL_DIV),
POWER_EVENT_PTR(CMPLU_STALL_SCALAR),
POWER_EVENT_PTR(CMPLU_STALL_SCALAR_LONG),
POWER_EVENT_PTR(CMPLU_STALL_VECTOR),
POWER_EVENT_PTR(CMPLU_STALL_VECTOR_LONG),
POWER_EVENT_PTR(CMPLU_STALL_LSU),
POWER_EVENT_PTR(CMPLU_STALL_REJECT),
POWER_EVENT_PTR(CMPLU_STALL_ERAT_MISS),
POWER_EVENT_PTR(CMPLU_STALL_DCACHE_MISS),
POWER_EVENT_PTR(CMPLU_STALL_STORE),
POWER_EVENT_PTR(CMPLU_STALL_THRD),
POWER_EVENT_PTR(CMPLU_STALL_IFU),
POWER_EVENT_PTR(CMPLU_STALL_BRU),
POWER_EVENT_PTR(GCT_NOSLOT_IC_MISS),
POWER_EVENT_PTR(GCT_NOSLOT_BR_MPRED),
POWER_EVENT_PTR(GCT_NOSLOT_BR_MPRED_IC_MISS),
POWER_EVENT_PTR(GRP_CMPL),
POWER_EVENT_PTR(1PLUS_PPC_CMPL),
POWER_EVENT_PTR(CMPLU_STALL_DFU),
POWER_EVENT_PTR(RUN_CYC),
POWER_EVENT_PTR(RUN_INST_CMPL),
#include "power7-events-list.h"
#undef EVENT
NULL
};
static struct attribute_group power7_pmu_events_group = {
.name = "events",
.attrs = power7_events_attr,

View File

@ -39,13 +39,8 @@ bindir_relative = bin
bindir = $(prefix)/$(bindir_relative)
man_dir = $(prefix)/share/man
man_dir_SQ = '$(subst ','\'',$(man_dir))'
html_install = $(prefix)/share/kernelshark/html
html_install_SQ = '$(subst ','\'',$(html_install))'
img_install = $(prefix)/share/kernelshark/html/images
img_install_SQ = '$(subst ','\'',$(img_install))'
export man_dir man_dir_SQ html_install html_install_SQ INSTALL
export img_install img_install_SQ
export man_dir man_dir_SQ INSTALL
export DESTDIR DESTDIR_SQ
# copy a bit from Linux kbuild
@ -76,10 +71,7 @@ $(if $(BUILD_OUTPUT),, \
all: sub-make
gui: force
$(call build_output, all_cmd)
$(filter-out gui,$(MAKECMDGOALS)): sub-make
$(MAKECMDGOALS): sub-make
sub-make: force
$(call build_output, $(MAKECMDGOALS))
@ -189,6 +181,7 @@ $(obj)/%.o: $(src)/%.c
$(Q)$(call do_compile)
PEVENT_LIB_OBJS = event-parse.o trace-seq.o parse-filter.o parse-utils.o
PEVENT_LIB_OBJS += kbuffer-parse.o
ALL_OBJS = $(PEVENT_LIB_OBJS)
@ -258,9 +251,6 @@ define check_deps
$(RM) $@.$$$$
endef
$(gui_deps): ks_version.h
$(non_gui_deps): tc_version.h
$(all_deps): .%.d: $(src)/%.c
$(Q)$(call check_deps)
@ -300,7 +290,7 @@ define do_install
$(INSTALL) $1 '$(DESTDIR_SQ)$2'
endef
install_lib: all_cmd install_plugins install_python
install_lib: all_cmd
$(Q)$(call do_install,$(LIB_FILE),$(bindir_SQ))
install: install_lib

View File

@ -5450,10 +5450,9 @@ int pevent_register_print_function(struct pevent *pevent,
* If @id is >= 0, then it is used to find the event.
* else @sys_name and @event_name are used.
*/
int pevent_register_event_handler(struct pevent *pevent,
int id, char *sys_name, char *event_name,
pevent_event_handler_func func,
void *context)
int pevent_register_event_handler(struct pevent *pevent, int id,
const char *sys_name, const char *event_name,
pevent_event_handler_func func, void *context)
{
struct event_format *event;
struct event_handler *handle;

View File

@ -69,6 +69,7 @@ struct trace_seq {
};
void trace_seq_init(struct trace_seq *s);
void trace_seq_reset(struct trace_seq *s);
void trace_seq_destroy(struct trace_seq *s);
extern int trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
@ -399,6 +400,7 @@ struct pevent {
int cpus;
int long_size;
int page_size;
struct cmdline *cmdlines;
struct cmdline_list *cmdlist;
@ -561,7 +563,8 @@ int pevent_print_num_field(struct trace_seq *s, const char *fmt,
struct event_format *event, const char *name,
struct pevent_record *record, int err);
int pevent_register_event_handler(struct pevent *pevent, int id, char *sys_name, char *event_name,
int pevent_register_event_handler(struct pevent *pevent, int id,
const char *sys_name, const char *event_name,
pevent_event_handler_func func, void *context);
int pevent_register_print_function(struct pevent *pevent,
pevent_func_handler func,
@ -619,6 +622,16 @@ static inline void pevent_set_long_size(struct pevent *pevent, int long_size)
pevent->long_size = long_size;
}
static inline int pevent_get_page_size(struct pevent *pevent)
{
return pevent->page_size;
}
static inline void pevent_set_page_size(struct pevent *pevent, int _page_size)
{
pevent->page_size = _page_size;
}
static inline int pevent_is_file_bigendian(struct pevent *pevent)
{
return pevent->file_bigendian;

View File

@ -0,0 +1,732 @@
/*
* Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License (not later!)
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "kbuffer.h"
#define MISSING_EVENTS (1 << 31)
#define MISSING_STORED (1 << 30)
#define COMMIT_MASK ((1 << 27) - 1)
enum {
KBUFFER_FL_HOST_BIG_ENDIAN = (1<<0),
KBUFFER_FL_BIG_ENDIAN = (1<<1),
KBUFFER_FL_LONG_8 = (1<<2),
KBUFFER_FL_OLD_FORMAT = (1<<3),
};
#define ENDIAN_MASK (KBUFFER_FL_HOST_BIG_ENDIAN | KBUFFER_FL_BIG_ENDIAN)
/** kbuffer
* @timestamp - timestamp of current event
* @lost_events - # of lost events between this subbuffer and previous
* @flags - special flags of the kbuffer
* @subbuffer - pointer to the sub-buffer page
* @data - pointer to the start of data on the sub-buffer page
* @index - index from @data to the @curr event data
* @curr - offset from @data to the start of current event
* (includes metadata)
* @next - offset from @data to the start of next event
* @size - The size of data on @data
* @start - The offset from @subbuffer where @data lives
*
* @read_4 - Function to read 4 raw bytes (may swap)
* @read_8 - Function to read 8 raw bytes (may swap)
* @read_long - Function to read a long word (4 or 8 bytes with needed swap)
*/
struct kbuffer {
unsigned long long timestamp;
long long lost_events;
unsigned long flags;
void *subbuffer;
void *data;
unsigned int index;
unsigned int curr;
unsigned int next;
unsigned int size;
unsigned int start;
unsigned int (*read_4)(void *ptr);
unsigned long long (*read_8)(void *ptr);
unsigned long long (*read_long)(struct kbuffer *kbuf, void *ptr);
int (*next_event)(struct kbuffer *kbuf);
};
static void *zmalloc(size_t size)
{
return calloc(1, size);
}
static int host_is_bigendian(void)
{
unsigned char str[] = { 0x1, 0x2, 0x3, 0x4 };
unsigned int *ptr;
ptr = (unsigned int *)str;
return *ptr == 0x01020304;
}
static int do_swap(struct kbuffer *kbuf)
{
return ((kbuf->flags & KBUFFER_FL_HOST_BIG_ENDIAN) + kbuf->flags) &
ENDIAN_MASK;
}
static unsigned long long __read_8(void *ptr)
{
unsigned long long data = *(unsigned long long *)ptr;
return data;
}
static unsigned long long __read_8_sw(void *ptr)
{
unsigned long long data = *(unsigned long long *)ptr;
unsigned long long swap;
swap = ((data & 0xffULL) << 56) |
((data & (0xffULL << 8)) << 40) |
((data & (0xffULL << 16)) << 24) |
((data & (0xffULL << 24)) << 8) |
((data & (0xffULL << 32)) >> 8) |
((data & (0xffULL << 40)) >> 24) |
((data & (0xffULL << 48)) >> 40) |
((data & (0xffULL << 56)) >> 56);
return swap;
}
static unsigned int __read_4(void *ptr)
{
unsigned int data = *(unsigned int *)ptr;
return data;
}
static unsigned int __read_4_sw(void *ptr)
{
unsigned int data = *(unsigned int *)ptr;
unsigned int swap;
swap = ((data & 0xffULL) << 24) |
((data & (0xffULL << 8)) << 8) |
((data & (0xffULL << 16)) >> 8) |
((data & (0xffULL << 24)) >> 24);
return swap;
}
static unsigned long long read_8(struct kbuffer *kbuf, void *ptr)
{
return kbuf->read_8(ptr);
}
static unsigned int read_4(struct kbuffer *kbuf, void *ptr)
{
return kbuf->read_4(ptr);
}
static unsigned long long __read_long_8(struct kbuffer *kbuf, void *ptr)
{
return kbuf->read_8(ptr);
}
static unsigned long long __read_long_4(struct kbuffer *kbuf, void *ptr)
{
return kbuf->read_4(ptr);
}
static unsigned long long read_long(struct kbuffer *kbuf, void *ptr)
{
return kbuf->read_long(kbuf, ptr);
}
static int calc_index(struct kbuffer *kbuf, void *ptr)
{
return (unsigned long)ptr - (unsigned long)kbuf->data;
}
static int __next_event(struct kbuffer *kbuf);
/**
* kbuffer_alloc - allocat a new kbuffer
* @size; enum to denote size of word
* @endian: enum to denote endianness
*
* Allocates and returns a new kbuffer.
*/
struct kbuffer *
kbuffer_alloc(enum kbuffer_long_size size, enum kbuffer_endian endian)
{
struct kbuffer *kbuf;
int flags = 0;
switch (size) {
case KBUFFER_LSIZE_4:
break;
case KBUFFER_LSIZE_8:
flags |= KBUFFER_FL_LONG_8;
break;
default:
return NULL;
}
switch (endian) {
case KBUFFER_ENDIAN_LITTLE:
break;
case KBUFFER_ENDIAN_BIG:
flags |= KBUFFER_FL_BIG_ENDIAN;
break;
default:
return NULL;
}
kbuf = zmalloc(sizeof(*kbuf));
if (!kbuf)
return NULL;
kbuf->flags = flags;
if (host_is_bigendian())
kbuf->flags |= KBUFFER_FL_HOST_BIG_ENDIAN;
if (do_swap(kbuf)) {
kbuf->read_8 = __read_8_sw;
kbuf->read_4 = __read_4_sw;
} else {
kbuf->read_8 = __read_8;
kbuf->read_4 = __read_4;
}
if (kbuf->flags & KBUFFER_FL_LONG_8)
kbuf->read_long = __read_long_8;
else
kbuf->read_long = __read_long_4;
/* May be changed by kbuffer_set_old_format() */
kbuf->next_event = __next_event;
return kbuf;
}
/** kbuffer_free - free an allocated kbuffer
* @kbuf: The kbuffer to free
*
* Can take NULL as a parameter.
*/
void kbuffer_free(struct kbuffer *kbuf)
{
free(kbuf);
}
static unsigned int type4host(struct kbuffer *kbuf,
unsigned int type_len_ts)
{
if (kbuf->flags & KBUFFER_FL_BIG_ENDIAN)
return (type_len_ts >> 29) & 3;
else
return type_len_ts & 3;
}
static unsigned int len4host(struct kbuffer *kbuf,
unsigned int type_len_ts)
{
if (kbuf->flags & KBUFFER_FL_BIG_ENDIAN)
return (type_len_ts >> 27) & 7;
else
return (type_len_ts >> 2) & 7;
}
static unsigned int type_len4host(struct kbuffer *kbuf,
unsigned int type_len_ts)
{
if (kbuf->flags & KBUFFER_FL_BIG_ENDIAN)
return (type_len_ts >> 27) & ((1 << 5) - 1);
else
return type_len_ts & ((1 << 5) - 1);
}
static unsigned int ts4host(struct kbuffer *kbuf,
unsigned int type_len_ts)
{
if (kbuf->flags & KBUFFER_FL_BIG_ENDIAN)
return type_len_ts & ((1 << 27) - 1);
else
return type_len_ts >> 5;
}
/*
* Linux 2.6.30 and earlier (not much ealier) had a different
* ring buffer format. It should be obsolete, but we handle it anyway.
*/
enum old_ring_buffer_type {
OLD_RINGBUF_TYPE_PADDING,
OLD_RINGBUF_TYPE_TIME_EXTEND,
OLD_RINGBUF_TYPE_TIME_STAMP,
OLD_RINGBUF_TYPE_DATA,
};
static unsigned int old_update_pointers(struct kbuffer *kbuf)
{
unsigned long long extend;
unsigned int type_len_ts;
unsigned int type;
unsigned int len;
unsigned int delta;
unsigned int length;
void *ptr = kbuf->data + kbuf->curr;
type_len_ts = read_4(kbuf, ptr);
ptr += 4;
type = type4host(kbuf, type_len_ts);
len = len4host(kbuf, type_len_ts);
delta = ts4host(kbuf, type_len_ts);
switch (type) {
case OLD_RINGBUF_TYPE_PADDING:
kbuf->next = kbuf->size;
return 0;
case OLD_RINGBUF_TYPE_TIME_EXTEND:
extend = read_4(kbuf, ptr);
extend <<= TS_SHIFT;
extend += delta;
delta = extend;
ptr += 4;
break;
case OLD_RINGBUF_TYPE_TIME_STAMP:
/* should never happen! */
kbuf->curr = kbuf->size;
kbuf->next = kbuf->size;
kbuf->index = kbuf->size;
return -1;
default:
if (len)
length = len * 4;
else {
length = read_4(kbuf, ptr);
length -= 4;
ptr += 4;
}
break;
}
kbuf->timestamp += delta;
kbuf->index = calc_index(kbuf, ptr);
kbuf->next = kbuf->index + length;
return type;
}
static int __old_next_event(struct kbuffer *kbuf)
{
int type;
do {
kbuf->curr = kbuf->next;
if (kbuf->next >= kbuf->size)
return -1;
type = old_update_pointers(kbuf);
} while (type == OLD_RINGBUF_TYPE_TIME_EXTEND || type == OLD_RINGBUF_TYPE_PADDING);
return 0;
}
static unsigned int
translate_data(struct kbuffer *kbuf, void *data, void **rptr,
unsigned long long *delta, int *length)
{
unsigned long long extend;
unsigned int type_len_ts;
unsigned int type_len;
type_len_ts = read_4(kbuf, data);
data += 4;
type_len = type_len4host(kbuf, type_len_ts);
*delta = ts4host(kbuf, type_len_ts);
switch (type_len) {
case KBUFFER_TYPE_PADDING:
*length = read_4(kbuf, data);
data += *length;
break;
case KBUFFER_TYPE_TIME_EXTEND:
extend = read_4(kbuf, data);
data += 4;
extend <<= TS_SHIFT;
extend += *delta;
*delta = extend;
*length = 0;
break;
case KBUFFER_TYPE_TIME_STAMP:
data += 12;
*length = 0;
break;
case 0:
*length = read_4(kbuf, data) - 4;
*length = (*length + 3) & ~3;
data += 4;
break;
default:
*length = type_len * 4;
break;
}
*rptr = data;
return type_len;
}
static unsigned int update_pointers(struct kbuffer *kbuf)
{
unsigned long long delta;
unsigned int type_len;
int length;
void *ptr = kbuf->data + kbuf->curr;
type_len = translate_data(kbuf, ptr, &ptr, &delta, &length);
kbuf->timestamp += delta;
kbuf->index = calc_index(kbuf, ptr);
kbuf->next = kbuf->index + length;
return type_len;
}
/**
* kbuffer_translate_data - read raw data to get a record
* @swap: Set to 1 if bytes in words need to be swapped when read
* @data: The raw data to read
* @size: Address to store the size of the event data.
*
* Returns a pointer to the event data. To determine the entire
* record size (record metadata + data) just add the difference between
* @data and the returned value to @size.
*/
void *kbuffer_translate_data(int swap, void *data, unsigned int *size)
{
unsigned long long delta;
struct kbuffer kbuf;
int type_len;
int length;
void *ptr;
if (swap) {
kbuf.read_8 = __read_8_sw;
kbuf.read_4 = __read_4_sw;
kbuf.flags = host_is_bigendian() ? 0 : KBUFFER_FL_BIG_ENDIAN;
} else {
kbuf.read_8 = __read_8;
kbuf.read_4 = __read_4;
kbuf.flags = host_is_bigendian() ? KBUFFER_FL_BIG_ENDIAN: 0;
}
type_len = translate_data(&kbuf, data, &ptr, &delta, &length);
switch (type_len) {
case KBUFFER_TYPE_PADDING:
case KBUFFER_TYPE_TIME_EXTEND:
case KBUFFER_TYPE_TIME_STAMP:
return NULL;
};
*size = length;
return ptr;
}
static int __next_event(struct kbuffer *kbuf)
{
int type;
do {
kbuf->curr = kbuf->next;
if (kbuf->next >= kbuf->size)
return -1;
type = update_pointers(kbuf);
} while (type == KBUFFER_TYPE_TIME_EXTEND || type == KBUFFER_TYPE_PADDING);
return 0;
}
static int next_event(struct kbuffer *kbuf)
{
return kbuf->next_event(kbuf);
}
/**
* kbuffer_next_event - increment the current pointer
* @kbuf: The kbuffer to read
* @ts: Address to store the next record's timestamp (may be NULL to ignore)
*
* Increments the pointers into the subbuffer of the kbuffer to point to the
* next event so that the next kbuffer_read_event() will return a
* new event.
*
* Returns the data of the next event if a new event exists on the subbuffer,
* NULL otherwise.
*/
void *kbuffer_next_event(struct kbuffer *kbuf, unsigned long long *ts)
{
int ret;
if (!kbuf || !kbuf->subbuffer)
return NULL;
ret = next_event(kbuf);
if (ret < 0)
return NULL;
if (ts)
*ts = kbuf->timestamp;
return kbuf->data + kbuf->index;
}
/**
* kbuffer_load_subbuffer - load a new subbuffer into the kbuffer
* @kbuf: The kbuffer to load
* @subbuffer: The subbuffer to load into @kbuf.
*
* Load a new subbuffer (page) into @kbuf. This will reset all
* the pointers and update the @kbuf timestamp. The next read will
* return the first event on @subbuffer.
*
* Returns 0 on succes, -1 otherwise.
*/
int kbuffer_load_subbuffer(struct kbuffer *kbuf, void *subbuffer)
{
unsigned long long flags;
void *ptr = subbuffer;
if (!kbuf || !subbuffer)
return -1;
kbuf->subbuffer = subbuffer;
kbuf->timestamp = read_8(kbuf, ptr);
ptr += 8;
kbuf->curr = 0;
if (kbuf->flags & KBUFFER_FL_LONG_8)
kbuf->start = 16;
else
kbuf->start = 12;
kbuf->data = subbuffer + kbuf->start;
flags = read_long(kbuf, ptr);
kbuf->size = (unsigned int)flags & COMMIT_MASK;
if (flags & MISSING_EVENTS) {
if (flags & MISSING_STORED) {
ptr = kbuf->data + kbuf->size;
kbuf->lost_events = read_long(kbuf, ptr);
} else
kbuf->lost_events = -1;
} else
kbuf->lost_events = 0;
kbuf->index = 0;
kbuf->next = 0;
next_event(kbuf);
return 0;
}
/**
* kbuffer_read_event - read the next event in the kbuffer subbuffer
* @kbuf: The kbuffer to read from
* @ts: The address to store the timestamp of the event (may be NULL to ignore)
*
* Returns a pointer to the data part of the current event.
* NULL if no event is left on the subbuffer.
*/
void *kbuffer_read_event(struct kbuffer *kbuf, unsigned long long *ts)
{
if (!kbuf || !kbuf->subbuffer)
return NULL;
if (kbuf->curr >= kbuf->size)
return NULL;
if (ts)
*ts = kbuf->timestamp;
return kbuf->data + kbuf->index;
}
/**
* kbuffer_timestamp - Return the timestamp of the current event
* @kbuf: The kbuffer to read from
*
* Returns the timestamp of the current (next) event.
*/
unsigned long long kbuffer_timestamp(struct kbuffer *kbuf)
{
return kbuf->timestamp;
}
/**
* kbuffer_read_at_offset - read the event that is at offset
* @kbuf: The kbuffer to read from
* @offset: The offset into the subbuffer
* @ts: The address to store the timestamp of the event (may be NULL to ignore)
*
* The @offset must be an index from the @kbuf subbuffer beginning.
* If @offset is bigger than the stored subbuffer, NULL will be returned.
*
* Returns the data of the record that is at @offset. Note, @offset does
* not need to be the start of the record, the offset just needs to be
* in the record (or beginning of it).
*
* Note, the kbuf timestamp and pointers are updated to the
* returned record. That is, kbuffer_read_event() will return the same
* data and timestamp, and kbuffer_next_event() will increment from
* this record.
*/
void *kbuffer_read_at_offset(struct kbuffer *kbuf, int offset,
unsigned long long *ts)
{
void *data;
if (offset < kbuf->start)
offset = 0;
else
offset -= kbuf->start;
/* Reset the buffer */
kbuffer_load_subbuffer(kbuf, kbuf->subbuffer);
while (kbuf->curr < offset) {
data = kbuffer_next_event(kbuf, ts);
if (!data)
break;
}
return data;
}
/**
* kbuffer_subbuffer_size - the size of the loaded subbuffer
* @kbuf: The kbuffer to read from
*
* Returns the size of the subbuffer. Note, this size is
* where the last event resides. The stored subbuffer may actually be
* bigger due to padding and such.
*/
int kbuffer_subbuffer_size(struct kbuffer *kbuf)
{
return kbuf->size;
}
/**
* kbuffer_curr_index - Return the index of the record
* @kbuf: The kbuffer to read from
*
* Returns the index from the start of the data part of
* the subbuffer to the current location. Note this is not
* from the start of the subbuffer. An index of zero will
* point to the first record. Use kbuffer_curr_offset() for
* the actually offset (that can be used by kbuffer_read_at_offset())
*/
int kbuffer_curr_index(struct kbuffer *kbuf)
{
return kbuf->curr;
}
/**
* kbuffer_curr_offset - Return the offset of the record
* @kbuf: The kbuffer to read from
*
* Returns the offset from the start of the subbuffer to the
* current location.
*/
int kbuffer_curr_offset(struct kbuffer *kbuf)
{
return kbuf->curr + kbuf->start;
}
/**
* kbuffer_event_size - return the size of the event data
* @kbuf: The kbuffer to read
*
* Returns the size of the event data (the payload not counting
* the meta data of the record) of the current event.
*/
int kbuffer_event_size(struct kbuffer *kbuf)
{
return kbuf->next - kbuf->index;
}
/**
* kbuffer_curr_size - return the size of the entire record
* @kbuf: The kbuffer to read
*
* Returns the size of the entire record (meta data and payload)
* of the current event.
*/
int kbuffer_curr_size(struct kbuffer *kbuf)
{
return kbuf->next - kbuf->curr;
}
/**
* kbuffer_missed_events - return the # of missed events from last event.
* @kbuf: The kbuffer to read from
*
* Returns the # of missed events (if recorded) before the current
* event. Note, only events on the beginning of a subbuffer can
* have missed events, all other events within the buffer will be
* zero.
*/
int kbuffer_missed_events(struct kbuffer *kbuf)
{
/* Only the first event can have missed events */
if (kbuf->curr)
return 0;
return kbuf->lost_events;
}
/**
* kbuffer_set_old_forma - set the kbuffer to use the old format parsing
* @kbuf: The kbuffer to set
*
* This is obsolete (or should be). The first kernels to use the
* new ring buffer had a slightly different ring buffer format
* (2.6.30 and earlier). It is still somewhat supported by kbuffer,
* but should not be counted on in the future.
*/
void kbuffer_set_old_format(struct kbuffer *kbuf)
{
kbuf->flags |= KBUFFER_FL_OLD_FORMAT;
kbuf->next_event = __old_next_event;
}

View File

@ -0,0 +1,67 @@
/*
* Copyright (C) 2012 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License (not later!)
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#ifndef _KBUFFER_H
#define _KBUFFER_H
#ifndef TS_SHIFT
#define TS_SHIFT 27
#endif
enum kbuffer_endian {
KBUFFER_ENDIAN_BIG,
KBUFFER_ENDIAN_LITTLE,
};
enum kbuffer_long_size {
KBUFFER_LSIZE_4,
KBUFFER_LSIZE_8,
};
enum {
KBUFFER_TYPE_PADDING = 29,
KBUFFER_TYPE_TIME_EXTEND = 30,
KBUFFER_TYPE_TIME_STAMP = 31,
};
struct kbuffer;
struct kbuffer *kbuffer_alloc(enum kbuffer_long_size size, enum kbuffer_endian endian);
void kbuffer_free(struct kbuffer *kbuf);
int kbuffer_load_subbuffer(struct kbuffer *kbuf, void *subbuffer);
void *kbuffer_read_event(struct kbuffer *kbuf, unsigned long long *ts);
void *kbuffer_next_event(struct kbuffer *kbuf, unsigned long long *ts);
unsigned long long kbuffer_timestamp(struct kbuffer *kbuf);
void *kbuffer_translate_data(int swap, void *data, unsigned int *size);
void *kbuffer_read_at_offset(struct kbuffer *kbuf, int offset, unsigned long long *ts);
int kbuffer_curr_index(struct kbuffer *kbuf);
int kbuffer_curr_offset(struct kbuffer *kbuf);
int kbuffer_curr_size(struct kbuffer *kbuf);
int kbuffer_event_size(struct kbuffer *kbuf);
int kbuffer_missed_events(struct kbuffer *kbuf);
int kbuffer_subbuffer_size(struct kbuffer *kbuf);
void kbuffer_set_old_format(struct kbuffer *kbuf);
#endif /* _K_BUFFER_H */

View File

@ -48,6 +48,19 @@ void trace_seq_init(struct trace_seq *s)
s->buffer = malloc_or_die(s->buffer_size);
}
/**
* trace_seq_reset - re-initialize the trace_seq structure
* @s: a pointer to the trace_seq structure to reset
*/
void trace_seq_reset(struct trace_seq *s)
{
if (!s)
return;
TRACE_SEQ_CHECK(s);
s->len = 0;
s->readpos = 0;
}
/**
* trace_seq_destroy - free up memory of a trace_seq
* @s: a pointer to the trace_seq to free the buffer

View File

@ -3,17 +3,17 @@ perf-diff(1)
NAME
----
perf-diff - Read two perf.data files and display the differential profile
perf-diff - Read perf.data files and display the differential profile
SYNOPSIS
--------
[verse]
'perf diff' [oldfile] [newfile]
'perf diff' [baseline file] [data file1] [[data file2] ... ]
DESCRIPTION
-----------
This command displays the performance difference amongst two perf.data files
captured via perf record.
This command displays the performance difference amongst two or more perf.data
files captured via perf record.
If no parameters are passed it will assume perf.data.old and perf.data.
@ -75,8 +75,6 @@ OPTIONS
-c::
--compute::
Differential computation selection - delta,ratio,wdiff (default is delta).
If '+' is specified as a first character, the output is sorted based
on the computation results.
See COMPARISON METHODS section for more info.
-p::
@ -87,6 +85,63 @@ OPTIONS
--formula::
Show formula for given computation.
-o::
--order::
Specify compute sorting column number.
COMPARISON
----------
The comparison is governed by the baseline file. The baseline perf.data
file is iterated for samples. All other perf.data files specified on
the command line are searched for the baseline sample pair. If the pair
is found, specified computation is made and result is displayed.
All samples from non-baseline perf.data files, that do not match any
baseline entry, are displayed with empty space within baseline column
and possible computation results (delta) in their related column.
Example files samples:
- file A with samples f1, f2, f3, f4, f6
- file B with samples f2, f4, f5
- file C with samples f1, f2, f5
Example output:
x - computation takes place for pair
b - baseline sample percentage
- perf diff A B C
baseline/A compute/B compute/C samples
---------------------------------------
b x f1
b x x f2
b f3
b x f4
b f6
x x f5
- perf diff B A C
baseline/B compute/A compute/C samples
---------------------------------------
b x x f2
b x f4
b x f5
x x f1
x f3
x f6
- perf diff C B A
baseline/C compute/B compute/A samples
---------------------------------------
b x f1
b x x f2
b x f5
x f3
x x f4
x f6
COMPARISON METHODS
------------------
delta
@ -96,7 +151,7 @@ If specified the 'Delta' column is displayed with value 'd' computed as:
d = A->period_percent - B->period_percent
with:
- A/B being matching hist entry from first/second file specified
- A/B being matching hist entry from data/baseline file specified
(or perf.data/perf.data.old) respectively.
- period_percent being the % of the hist entry period value within
@ -109,24 +164,26 @@ If specified the 'Ratio' column is displayed with value 'r' computed as:
r = A->period / B->period
with:
- A/B being matching hist entry from first/second file specified
- A/B being matching hist entry from data/baseline file specified
(or perf.data/perf.data.old) respectively.
- period being the hist entry period value
wdiff
~~~~~
wdiff:WEIGHT-B,WEIGHT-A
~~~~~~~~~~~~~~~~~~~~~~~
If specified the 'Weighted diff' column is displayed with value 'd' computed as:
d = B->period * WEIGHT-A - A->period * WEIGHT-B
- A/B being matching hist entry from first/second file specified
- A/B being matching hist entry from data/baseline file specified
(or perf.data/perf.data.old) respectively.
- period being the hist entry period value
- WEIGHT-A/WEIGHT-B being user suplied weights in the the '-c' option
behind ':' separator like '-c wdiff:1,2'.
- WIEGHT-A being the weight of the data file
- WIEGHT-B being the weight of the baseline data file
SEE ALSO
--------

View File

@ -8,7 +8,7 @@ perf-list - List all symbolic event types
SYNOPSIS
--------
[verse]
'perf list' [hw|sw|cache|tracepoint|event_glob]
'perf list' [hw|sw|cache|tracepoint|pmu|event_glob]
DESCRIPTION
-----------
@ -104,6 +104,8 @@ To limit the list use:
'subsys_glob:event_glob' to filter by tracepoint subsystems such as sched,
block, etc.
. 'pmu' to print the kernel supplied PMU events.
. If none of the above is matched, it will apply the supplied glob to all
events, printing the ones that match.

View File

@ -135,6 +135,11 @@ OPTIONS
--inverted::
alias for inverted caller based call graph.
--ignore-callees=<regex>::
Ignore callees of the function(s) matching the given regex.
This has the effect of collecting the callers of each such
function into one place in the call-graph tree.
--pretty=<key>::
Pretty printing style. key: normal, raw

View File

@ -155,6 +155,11 @@ Default is to monitor all CPUS.
Default: fractal,0.5,callee.
--ignore-callees=<regex>::
Ignore callees of the function(s) matching the given regex.
This has the effect of collecting the callers of each such
function into one place in the call-graph tree.
--percent-limit::
Do not show entries which have an overhead under that percent.
(Default: 0).

View File

@ -124,7 +124,7 @@ strip-libs = $(filter-out -l%,$(1))
ifneq ($(OUTPUT),)
TE_PATH=$(OUTPUT)
ifneq ($(subdir),)
LK_PATH=$(objtree)/lib/lk/
LK_PATH=$(OUTPUT)/../lib/lk/
else
LK_PATH=$(OUTPUT)
endif
@ -281,7 +281,7 @@ LIB_H += util/cpumap.h
LIB_H += util/top.h
LIB_H += $(ARCH_INCLUDE)
LIB_H += util/cgroup.h
LIB_H += $(TRACE_EVENT_DIR)event-parse.h
LIB_H += $(LIB_INCLUDE)traceevent/event-parse.h
LIB_H += util/target.h
LIB_H += util/rblist.h
LIB_H += util/intlist.h

View File

@ -18,15 +18,53 @@
#include "util/util.h"
#include <stdlib.h>
#include <math.h>
static char const *input_old = "perf.data.old",
*input_new = "perf.data";
static char diff__default_sort_order[] = "dso,symbol";
static bool force;
/* Diff command specific HPP columns. */
enum {
PERF_HPP_DIFF__BASELINE,
PERF_HPP_DIFF__PERIOD,
PERF_HPP_DIFF__PERIOD_BASELINE,
PERF_HPP_DIFF__DELTA,
PERF_HPP_DIFF__RATIO,
PERF_HPP_DIFF__WEIGHTED_DIFF,
PERF_HPP_DIFF__FORMULA,
PERF_HPP_DIFF__MAX_INDEX
};
struct diff_hpp_fmt {
struct perf_hpp_fmt fmt;
int idx;
char *header;
int header_width;
};
struct data__file {
struct perf_session *session;
const char *file;
int idx;
struct hists *hists;
struct diff_hpp_fmt fmt[PERF_HPP_DIFF__MAX_INDEX];
};
static struct data__file *data__files;
static int data__files_cnt;
#define data__for_each_file_start(i, d, s) \
for (i = s, d = &data__files[s]; \
i < data__files_cnt; \
i++, d = &data__files[i])
#define data__for_each_file(i, d) data__for_each_file_start(i, d, 0)
#define data__for_each_file_new(i, d) data__for_each_file_start(i, d, 1)
static char diff__default_sort_order[] = "dso,symbol";
static bool force;
static bool show_period;
static bool show_formula;
static bool show_baseline_only;
static bool sort_compute;
static unsigned int sort_compute;
static s64 compute_wdiff_w1;
static s64 compute_wdiff_w2;
@ -46,6 +84,47 @@ const char *compute_names[COMPUTE_MAX] = {
static int compute;
static int compute_2_hpp[COMPUTE_MAX] = {
[COMPUTE_DELTA] = PERF_HPP_DIFF__DELTA,
[COMPUTE_RATIO] = PERF_HPP_DIFF__RATIO,
[COMPUTE_WEIGHTED_DIFF] = PERF_HPP_DIFF__WEIGHTED_DIFF,
};
#define MAX_COL_WIDTH 70
static struct header_column {
const char *name;
int width;
} columns[PERF_HPP_DIFF__MAX_INDEX] = {
[PERF_HPP_DIFF__BASELINE] = {
.name = "Baseline",
},
[PERF_HPP_DIFF__PERIOD] = {
.name = "Period",
.width = 14,
},
[PERF_HPP_DIFF__PERIOD_BASELINE] = {
.name = "Base period",
.width = 14,
},
[PERF_HPP_DIFF__DELTA] = {
.name = "Delta",
.width = 7,
},
[PERF_HPP_DIFF__RATIO] = {
.name = "Ratio",
.width = 14,
},
[PERF_HPP_DIFF__WEIGHTED_DIFF] = {
.name = "Weighted diff",
.width = 14,
},
[PERF_HPP_DIFF__FORMULA] = {
.name = "Formula",
.width = MAX_COL_WIDTH,
}
};
static int setup_compute_opt_wdiff(char *opt)
{
char *w1_str = opt;
@ -109,13 +188,6 @@ static int setup_compute(const struct option *opt, const char *str,
return 0;
}
if (*str == '+') {
sort_compute = true;
cstr = (char *) ++str;
if (!*str)
return 0;
}
option = strchr(str, ':');
if (option) {
unsigned len = option++ - str;
@ -145,42 +217,42 @@ static int setup_compute(const struct option *opt, const char *str,
return -EINVAL;
}
double perf_diff__period_percent(struct hist_entry *he, u64 period)
static double period_percent(struct hist_entry *he, u64 period)
{
u64 total = he->hists->stats.total_period;
return (period * 100.0) / total;
}
double perf_diff__compute_delta(struct hist_entry *he, struct hist_entry *pair)
static double compute_delta(struct hist_entry *he, struct hist_entry *pair)
{
double new_percent = perf_diff__period_percent(he, he->stat.period);
double old_percent = perf_diff__period_percent(pair, pair->stat.period);
double old_percent = period_percent(he, he->stat.period);
double new_percent = period_percent(pair, pair->stat.period);
he->diff.period_ratio_delta = new_percent - old_percent;
he->diff.computed = true;
return he->diff.period_ratio_delta;
pair->diff.period_ratio_delta = new_percent - old_percent;
pair->diff.computed = true;
return pair->diff.period_ratio_delta;
}
double perf_diff__compute_ratio(struct hist_entry *he, struct hist_entry *pair)
static double compute_ratio(struct hist_entry *he, struct hist_entry *pair)
{
double new_period = he->stat.period;
double old_period = pair->stat.period;
double old_period = he->stat.period ?: 1;
double new_period = pair->stat.period;
he->diff.computed = true;
he->diff.period_ratio = new_period / old_period;
return he->diff.period_ratio;
pair->diff.computed = true;
pair->diff.period_ratio = new_period / old_period;
return pair->diff.period_ratio;
}
s64 perf_diff__compute_wdiff(struct hist_entry *he, struct hist_entry *pair)
static s64 compute_wdiff(struct hist_entry *he, struct hist_entry *pair)
{
u64 new_period = he->stat.period;
u64 old_period = pair->stat.period;
u64 old_period = he->stat.period;
u64 new_period = pair->stat.period;
he->diff.computed = true;
he->diff.wdiff = new_period * compute_wdiff_w2 -
old_period * compute_wdiff_w1;
pair->diff.computed = true;
pair->diff.wdiff = new_period * compute_wdiff_w2 -
old_period * compute_wdiff_w1;
return he->diff.wdiff;
return pair->diff.wdiff;
}
static int formula_delta(struct hist_entry *he, struct hist_entry *pair,
@ -189,15 +261,15 @@ static int formula_delta(struct hist_entry *he, struct hist_entry *pair,
return scnprintf(buf, size,
"(%" PRIu64 " * 100 / %" PRIu64 ") - "
"(%" PRIu64 " * 100 / %" PRIu64 ")",
he->stat.period, he->hists->stats.total_period,
pair->stat.period, pair->hists->stats.total_period);
pair->stat.period, pair->hists->stats.total_period,
he->stat.period, he->hists->stats.total_period);
}
static int formula_ratio(struct hist_entry *he, struct hist_entry *pair,
char *buf, size_t size)
{
double new_period = he->stat.period;
double old_period = pair->stat.period;
double old_period = he->stat.period;
double new_period = pair->stat.period;
return scnprintf(buf, size, "%.0F / %.0F", new_period, old_period);
}
@ -205,16 +277,16 @@ static int formula_ratio(struct hist_entry *he, struct hist_entry *pair,
static int formula_wdiff(struct hist_entry *he, struct hist_entry *pair,
char *buf, size_t size)
{
u64 new_period = he->stat.period;
u64 old_period = pair->stat.period;
u64 old_period = he->stat.period;
u64 new_period = pair->stat.period;
return scnprintf(buf, size,
"(%" PRIu64 " * " "%" PRId64 ") - (%" PRIu64 " * " "%" PRId64 ")",
new_period, compute_wdiff_w2, old_period, compute_wdiff_w1);
}
int perf_diff__formula(struct hist_entry *he, struct hist_entry *pair,
char *buf, size_t size)
static int formula_fprintf(struct hist_entry *he, struct hist_entry *pair,
char *buf, size_t size)
{
switch (compute) {
case COMPUTE_DELTA:
@ -299,6 +371,29 @@ static void perf_evlist__collapse_resort(struct perf_evlist *evlist)
}
}
static struct hist_entry*
get_pair_data(struct hist_entry *he, struct data__file *d)
{
if (hist_entry__has_pairs(he)) {
struct hist_entry *pair;
list_for_each_entry(pair, &he->pairs.head, pairs.node)
if (pair->hists == d->hists)
return pair;
}
return NULL;
}
static struct hist_entry*
get_pair_fmt(struct hist_entry *he, struct diff_hpp_fmt *dfmt)
{
void *ptr = dfmt - dfmt->idx;
struct data__file *d = container_of(ptr, struct data__file, fmt);
return get_pair_data(he, d);
}
static void hists__baseline_only(struct hists *hists)
{
struct rb_root *root;
@ -333,22 +428,24 @@ static void hists__precompute(struct hists *hists)
next = rb_first(root);
while (next != NULL) {
struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node_in);
struct hist_entry *pair = hist_entry__next_pair(he);
struct hist_entry *he, *pair;
he = rb_entry(next, struct hist_entry, rb_node_in);
next = rb_next(&he->rb_node_in);
pair = get_pair_data(he, &data__files[sort_compute]);
if (!pair)
continue;
switch (compute) {
case COMPUTE_DELTA:
perf_diff__compute_delta(he, pair);
compute_delta(he, pair);
break;
case COMPUTE_RATIO:
perf_diff__compute_ratio(he, pair);
compute_ratio(he, pair);
break;
case COMPUTE_WEIGHTED_DIFF:
perf_diff__compute_wdiff(he, pair);
compute_wdiff(he, pair);
break;
default:
BUG_ON(1);
@ -367,7 +464,7 @@ static int64_t cmp_doubles(double l, double r)
}
static int64_t
hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right,
__hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right,
int c)
{
switch (c) {
@ -399,6 +496,36 @@ hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right,
return 0;
}
static int64_t
hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right,
int c)
{
bool pairs_left = hist_entry__has_pairs(left);
bool pairs_right = hist_entry__has_pairs(right);
struct hist_entry *p_right, *p_left;
if (!pairs_left && !pairs_right)
return 0;
if (!pairs_left || !pairs_right)
return pairs_left ? -1 : 1;
p_left = get_pair_data(left, &data__files[sort_compute]);
p_right = get_pair_data(right, &data__files[sort_compute]);
if (!p_left && !p_right)
return 0;
if (!p_left || !p_right)
return p_left ? -1 : 1;
/*
* We have 2 entries of same kind, let's
* make the data comparison.
*/
return __hist_entry__cmp_compute(p_left, p_right, c);
}
static void insert_hist_entry_by_compute(struct rb_root *root,
struct hist_entry *he,
int c)
@ -448,75 +575,121 @@ static void hists__compute_resort(struct hists *hists)
}
}
static void hists__process(struct hists *old, struct hists *new)
static void hists__process(struct hists *hists)
{
hists__match(new, old);
if (show_baseline_only)
hists__baseline_only(new);
else
hists__link(new, old);
hists__baseline_only(hists);
if (sort_compute) {
hists__precompute(new);
hists__compute_resort(new);
hists__precompute(hists);
hists__compute_resort(hists);
} else {
hists__output_resort(new);
hists__output_resort(hists);
}
hists__fprintf(new, true, 0, 0, 0, stdout);
hists__fprintf(hists, true, 0, 0, 0, stdout);
}
static void data__fprintf(void)
{
struct data__file *d;
int i;
fprintf(stdout, "# Data files:\n");
data__for_each_file(i, d)
fprintf(stdout, "# [%d] %s %s\n",
d->idx, d->file,
!d->idx ? "(Baseline)" : "");
fprintf(stdout, "#\n");
}
static void data_process(void)
{
struct perf_evlist *evlist_base = data__files[0].session->evlist;
struct perf_evsel *evsel_base;
bool first = true;
list_for_each_entry(evsel_base, &evlist_base->entries, node) {
struct data__file *d;
int i;
data__for_each_file_new(i, d) {
struct perf_evlist *evlist = d->session->evlist;
struct perf_evsel *evsel;
evsel = evsel_match(evsel_base, evlist);
if (!evsel)
continue;
d->hists = &evsel->hists;
hists__match(&evsel_base->hists, &evsel->hists);
if (!show_baseline_only)
hists__link(&evsel_base->hists,
&evsel->hists);
}
fprintf(stdout, "%s# Event '%s'\n#\n", first ? "" : "\n",
perf_evsel__name(evsel_base));
first = false;
if (verbose || data__files_cnt > 2)
data__fprintf();
hists__process(&evsel_base->hists);
}
}
static void data__free(struct data__file *d)
{
int col;
for (col = 0; col < PERF_HPP_DIFF__MAX_INDEX; col++) {
struct diff_hpp_fmt *fmt = &d->fmt[col];
free(fmt->header);
}
}
static int __cmd_diff(void)
{
int ret, i;
#define older (session[0])
#define newer (session[1])
struct perf_session *session[2];
struct perf_evlist *evlist_new, *evlist_old;
struct perf_evsel *evsel;
bool first = true;
struct data__file *d;
int ret = -EINVAL, i;
older = perf_session__new(input_old, O_RDONLY, force, false,
&tool);
newer = perf_session__new(input_new, O_RDONLY, force, false,
&tool);
if (session[0] == NULL || session[1] == NULL)
return -ENOMEM;
for (i = 0; i < 2; ++i) {
ret = perf_session__process_events(session[i], &tool);
if (ret)
data__for_each_file(i, d) {
d->session = perf_session__new(d->file, O_RDONLY, force,
false, &tool);
if (!d->session) {
pr_err("Failed to open %s\n", d->file);
ret = -ENOMEM;
goto out_delete;
}
ret = perf_session__process_events(d->session, &tool);
if (ret) {
pr_err("Failed to process %s\n", d->file);
goto out_delete;
}
perf_evlist__collapse_resort(d->session->evlist);
}
evlist_old = older->evlist;
evlist_new = newer->evlist;
data_process();
perf_evlist__collapse_resort(evlist_old);
perf_evlist__collapse_resort(evlist_new);
out_delete:
data__for_each_file(i, d) {
if (d->session)
perf_session__delete(d->session);
list_for_each_entry(evsel, &evlist_new->entries, node) {
struct perf_evsel *evsel_old;
evsel_old = evsel_match(evsel, evlist_old);
if (!evsel_old)
continue;
fprintf(stdout, "%s# Event '%s'\n#\n", first ? "" : "\n",
perf_evsel__name(evsel));
first = false;
hists__process(&evsel_old->hists, &evsel->hists);
data__free(d);
}
out_delete:
for (i = 0; i < 2; ++i)
perf_session__delete(session[i]);
free(data__files);
return ret;
#undef older
#undef newer
}
static const char * const diff_usage[] = {
@ -555,61 +728,310 @@ static const struct option options[] = {
"columns '.' is reserved."),
OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
"Look for files with symbols relative to this directory"),
OPT_UINTEGER('o', "order", &sort_compute, "Specify compute sorting."),
OPT_END()
};
static void ui_init(void)
static double baseline_percent(struct hist_entry *he)
{
/*
* Display baseline/delta/ratio
* formula/periods columns.
*/
perf_hpp__column_enable(PERF_HPP__BASELINE);
struct hists *hists = he->hists;
return 100.0 * he->stat.period / hists->stats.total_period;
}
switch (compute) {
case COMPUTE_DELTA:
perf_hpp__column_enable(PERF_HPP__DELTA);
static int hpp__color_baseline(struct perf_hpp_fmt *fmt,
struct perf_hpp *hpp, struct hist_entry *he)
{
struct diff_hpp_fmt *dfmt =
container_of(fmt, struct diff_hpp_fmt, fmt);
double percent = baseline_percent(he);
char pfmt[20] = " ";
if (!he->dummy) {
scnprintf(pfmt, 20, "%%%d.2f%%%%", dfmt->header_width - 1);
return percent_color_snprintf(hpp->buf, hpp->size,
pfmt, percent);
} else
return scnprintf(hpp->buf, hpp->size, "%*s",
dfmt->header_width, pfmt);
}
static int hpp__entry_baseline(struct hist_entry *he, char *buf, size_t size)
{
double percent = baseline_percent(he);
const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%";
int ret = 0;
if (!he->dummy)
ret = scnprintf(buf, size, fmt, percent);
return ret;
}
static void
hpp__entry_unpair(struct hist_entry *he, int idx, char *buf, size_t size)
{
switch (idx) {
case PERF_HPP_DIFF__PERIOD_BASELINE:
scnprintf(buf, size, "%" PRIu64, he->stat.period);
break;
case COMPUTE_RATIO:
perf_hpp__column_enable(PERF_HPP__RATIO);
default:
break;
case COMPUTE_WEIGHTED_DIFF:
perf_hpp__column_enable(PERF_HPP__WEIGHTED_DIFF);
}
}
static void
hpp__entry_pair(struct hist_entry *he, struct hist_entry *pair,
int idx, char *buf, size_t size)
{
double diff;
double ratio;
s64 wdiff;
switch (idx) {
case PERF_HPP_DIFF__DELTA:
if (pair->diff.computed)
diff = pair->diff.period_ratio_delta;
else
diff = compute_delta(he, pair);
if (fabs(diff) >= 0.01)
scnprintf(buf, size, "%+4.2F%%", diff);
break;
case PERF_HPP_DIFF__RATIO:
/* No point for ratio number if we are dummy.. */
if (he->dummy)
break;
if (pair->diff.computed)
ratio = pair->diff.period_ratio;
else
ratio = compute_ratio(he, pair);
if (ratio > 0.0)
scnprintf(buf, size, "%14.6F", ratio);
break;
case PERF_HPP_DIFF__WEIGHTED_DIFF:
/* No point for wdiff number if we are dummy.. */
if (he->dummy)
break;
if (pair->diff.computed)
wdiff = pair->diff.wdiff;
else
wdiff = compute_wdiff(he, pair);
if (wdiff != 0)
scnprintf(buf, size, "%14ld", wdiff);
break;
case PERF_HPP_DIFF__FORMULA:
formula_fprintf(he, pair, buf, size);
break;
case PERF_HPP_DIFF__PERIOD:
scnprintf(buf, size, "%" PRIu64, pair->stat.period);
break;
default:
BUG_ON(1);
};
}
if (show_formula)
perf_hpp__column_enable(PERF_HPP__FORMULA);
static void
__hpp__entry_global(struct hist_entry *he, struct diff_hpp_fmt *dfmt,
char *buf, size_t size)
{
struct hist_entry *pair = get_pair_fmt(he, dfmt);
int idx = dfmt->idx;
if (show_period) {
perf_hpp__column_enable(PERF_HPP__PERIOD);
perf_hpp__column_enable(PERF_HPP__PERIOD_BASELINE);
/* baseline is special */
if (idx == PERF_HPP_DIFF__BASELINE)
hpp__entry_baseline(he, buf, size);
else {
if (pair)
hpp__entry_pair(he, pair, idx, buf, size);
else
hpp__entry_unpair(he, idx, buf, size);
}
}
static int hpp__entry_global(struct perf_hpp_fmt *_fmt, struct perf_hpp *hpp,
struct hist_entry *he)
{
struct diff_hpp_fmt *dfmt =
container_of(_fmt, struct diff_hpp_fmt, fmt);
char buf[MAX_COL_WIDTH] = " ";
__hpp__entry_global(he, dfmt, buf, MAX_COL_WIDTH);
if (symbol_conf.field_sep)
return scnprintf(hpp->buf, hpp->size, "%s", buf);
else
return scnprintf(hpp->buf, hpp->size, "%*s",
dfmt->header_width, buf);
}
static int hpp__header(struct perf_hpp_fmt *fmt,
struct perf_hpp *hpp)
{
struct diff_hpp_fmt *dfmt =
container_of(fmt, struct diff_hpp_fmt, fmt);
BUG_ON(!dfmt->header);
return scnprintf(hpp->buf, hpp->size, dfmt->header);
}
static int hpp__width(struct perf_hpp_fmt *fmt,
struct perf_hpp *hpp __maybe_unused)
{
struct diff_hpp_fmt *dfmt =
container_of(fmt, struct diff_hpp_fmt, fmt);
BUG_ON(dfmt->header_width <= 0);
return dfmt->header_width;
}
static void init_header(struct data__file *d, struct diff_hpp_fmt *dfmt)
{
#define MAX_HEADER_NAME 100
char buf_indent[MAX_HEADER_NAME];
char buf[MAX_HEADER_NAME];
const char *header = NULL;
int width = 0;
BUG_ON(dfmt->idx >= PERF_HPP_DIFF__MAX_INDEX);
header = columns[dfmt->idx].name;
width = columns[dfmt->idx].width;
/* Only our defined HPP fmts should appear here. */
BUG_ON(!header);
if (data__files_cnt > 2)
scnprintf(buf, MAX_HEADER_NAME, "%s/%d", header, d->idx);
#define NAME (data__files_cnt > 2 ? buf : header)
dfmt->header_width = width;
width = (int) strlen(NAME);
if (dfmt->header_width < width)
dfmt->header_width = width;
scnprintf(buf_indent, MAX_HEADER_NAME, "%*s",
dfmt->header_width, NAME);
dfmt->header = strdup(buf_indent);
#undef MAX_HEADER_NAME
#undef NAME
}
static void data__hpp_register(struct data__file *d, int idx)
{
struct diff_hpp_fmt *dfmt = &d->fmt[idx];
struct perf_hpp_fmt *fmt = &dfmt->fmt;
dfmt->idx = idx;
fmt->header = hpp__header;
fmt->width = hpp__width;
fmt->entry = hpp__entry_global;
/* TODO more colors */
if (idx == PERF_HPP_DIFF__BASELINE)
fmt->color = hpp__color_baseline;
init_header(d, dfmt);
perf_hpp__column_register(fmt);
}
static void ui_init(void)
{
struct data__file *d;
int i;
data__for_each_file(i, d) {
/*
* Baseline or compute realted columns:
*
* PERF_HPP_DIFF__BASELINE
* PERF_HPP_DIFF__DELTA
* PERF_HPP_DIFF__RATIO
* PERF_HPP_DIFF__WEIGHTED_DIFF
*/
data__hpp_register(d, i ? compute_2_hpp[compute] :
PERF_HPP_DIFF__BASELINE);
/*
* And the rest:
*
* PERF_HPP_DIFF__FORMULA
* PERF_HPP_DIFF__PERIOD
* PERF_HPP_DIFF__PERIOD_BASELINE
*/
if (show_formula && i)
data__hpp_register(d, PERF_HPP_DIFF__FORMULA);
if (show_period)
data__hpp_register(d, i ? PERF_HPP_DIFF__PERIOD :
PERF_HPP_DIFF__PERIOD_BASELINE);
}
}
static int data_init(int argc, const char **argv)
{
struct data__file *d;
static const char *defaults[] = {
"perf.data.old",
"perf.data",
};
bool use_default = true;
int i;
data__files_cnt = 2;
if (argc) {
if (argc == 1)
defaults[1] = argv[0];
else {
data__files_cnt = argc;
use_default = false;
}
} else if (symbol_conf.default_guest_vmlinux_name ||
symbol_conf.default_guest_kallsyms) {
defaults[0] = "perf.data.host";
defaults[1] = "perf.data.guest";
}
if (sort_compute >= (unsigned int) data__files_cnt) {
pr_err("Order option out of limit.\n");
return -EINVAL;
}
data__files = zalloc(sizeof(*data__files) * data__files_cnt);
if (!data__files)
return -ENOMEM;
data__for_each_file(i, d) {
d->file = use_default ? defaults[i] : argv[i];
d->idx = i;
}
return 0;
}
int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
{
sort_order = diff__default_sort_order;
argc = parse_options(argc, argv, options, diff_usage, 0);
if (argc) {
if (argc > 2)
usage_with_options(diff_usage, options);
if (argc == 2) {
input_old = argv[0];
input_new = argv[1];
} else
input_new = argv[0];
} else if (symbol_conf.default_guest_vmlinux_name ||
symbol_conf.default_guest_kallsyms) {
input_old = "perf.data.host";
input_new = "perf.data.guest";
}
if (symbol__init() < 0)
return -1;
if (data_init(argc, argv) < 0)
return -1;
ui_init();
if (setup_sorting() < 0)

View File

@ -38,8 +38,7 @@ struct event_entry {
};
static int perf_event__repipe_synth(struct perf_tool *tool,
union perf_event *event,
struct machine *machine __maybe_unused)
union perf_event *event)
{
struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
uint32_t size;
@ -65,39 +64,28 @@ static int perf_event__repipe_op2_synth(struct perf_tool *tool,
struct perf_session *session
__maybe_unused)
{
return perf_event__repipe_synth(tool, event, NULL);
return perf_event__repipe_synth(tool, event);
}
static int perf_event__repipe_event_type_synth(struct perf_tool *tool,
union perf_event *event)
{
return perf_event__repipe_synth(tool, event, NULL);
}
static int perf_event__repipe_tracing_data_synth(union perf_event *event,
struct perf_session *session
__maybe_unused)
{
return perf_event__repipe_synth(NULL, event, NULL);
}
static int perf_event__repipe_attr(union perf_event *event,
struct perf_evlist **pevlist __maybe_unused)
static int perf_event__repipe_attr(struct perf_tool *tool,
union perf_event *event,
struct perf_evlist **pevlist)
{
int ret;
ret = perf_event__process_attr(event, pevlist);
ret = perf_event__process_attr(tool, event, pevlist);
if (ret)
return ret;
return perf_event__repipe_synth(NULL, event, NULL);
return perf_event__repipe_synth(tool, event);
}
static int perf_event__repipe(struct perf_tool *tool,
union perf_event *event,
struct perf_sample *sample __maybe_unused,
struct machine *machine)
struct machine *machine __maybe_unused)
{
return perf_event__repipe_synth(tool, event, machine);
return perf_event__repipe_synth(tool, event);
}
typedef int (*inject_handler)(struct perf_tool *tool,
@ -119,7 +107,7 @@ static int perf_event__repipe_sample(struct perf_tool *tool,
build_id__mark_dso_hit(tool, event, sample, evsel, machine);
return perf_event__repipe_synth(tool, event, machine);
return perf_event__repipe_synth(tool, event);
}
static int perf_event__repipe_mmap(struct perf_tool *tool,
@ -148,13 +136,14 @@ static int perf_event__repipe_fork(struct perf_tool *tool,
return err;
}
static int perf_event__repipe_tracing_data(union perf_event *event,
static int perf_event__repipe_tracing_data(struct perf_tool *tool,
union perf_event *event,
struct perf_session *session)
{
int err;
perf_event__repipe_synth(NULL, event, NULL);
err = perf_event__process_tracing_data(event, session);
perf_event__repipe_synth(tool, event);
err = perf_event__process_tracing_data(tool, event, session);
return err;
}
@ -407,8 +396,8 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
.throttle = perf_event__repipe,
.unthrottle = perf_event__repipe,
.attr = perf_event__repipe_attr,
.event_type = perf_event__repipe_event_type_synth,
.tracing_data = perf_event__repipe_tracing_data_synth,
.tracing_data = perf_event__repipe_op2_synth,
.finished_round = perf_event__repipe_op2_synth,
.build_id = perf_event__repipe_op2_synth,
},
.input_name = "-",

View File

@ -313,7 +313,7 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
return -1;
}
dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
dump_printf(" ... thread: %s:%d\n", thread->comm, thread->tid);
if (evsel->handler.func != NULL) {
tracepoint_handler f = evsel->handler.func;

View File

@ -13,6 +13,7 @@
#include "util/parse-events.h"
#include "util/cache.h"
#include "util/pmu.h"
int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
{
@ -37,6 +38,8 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
else if (strcmp(argv[i], "cache") == 0 ||
strcmp(argv[i], "hwcache") == 0)
print_hwcache_events(NULL, false);
else if (strcmp(argv[i], "pmu") == 0)
print_pmu_events(NULL, false);
else if (strcmp(argv[i], "--raw-dump") == 0)
print_events(NULL, true);
else {

View File

@ -474,13 +474,6 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
goto out_delete_session;
}
err = perf_event__synthesize_event_types(tool, process_synthesized_event,
machine);
if (err < 0) {
pr_err("Couldn't synthesize event_types.\n");
goto out_delete_session;
}
if (have_tracepoints(&evsel_list->entries)) {
/*
* FIXME err <= 0 here actually means that
@ -904,7 +897,6 @@ const struct option record_options[] = {
int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
{
int err = -ENOMEM;
struct perf_evsel *pos;
struct perf_evlist *evsel_list;
struct perf_record *rec = &record;
char errbuf[BUFSIZ];
@ -968,11 +960,6 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0)
usage_with_options(record_usage, record_options);
list_for_each_entry(pos, &evsel_list->entries, node) {
if (perf_header__push_event(pos->attr.config, perf_evsel__name(pos)))
goto out_free_fd;
}
if (rec->opts.user_interval != ULLONG_MAX)
rec->opts.default_interval = rec->opts.user_interval;
if (rec->opts.user_freq != UINT_MAX)

View File

@ -89,7 +89,7 @@ static int perf_report__add_mem_hist_entry(struct perf_tool *tool,
if ((sort__has_parent || symbol_conf.use_callchain) &&
sample->callchain) {
err = machine__resolve_callchain(machine, evsel, al->thread,
sample, &parent);
sample, &parent, al);
if (err)
return err;
}
@ -180,7 +180,7 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
if ((sort__has_parent || symbol_conf.use_callchain)
&& sample->callchain) {
err = machine__resolve_callchain(machine, evsel, al->thread,
sample, &parent);
sample, &parent, al);
if (err)
return err;
}
@ -254,7 +254,7 @@ static int perf_evsel__add_hist_entry(struct perf_evsel *evsel,
if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) {
err = machine__resolve_callchain(machine, evsel, al->thread,
sample, &parent);
sample, &parent, al);
if (err)
return err;
}
@ -497,7 +497,7 @@ static int __cmd_report(struct perf_report *rep)
ret = perf_session__cpu_bitmap(session, rep->cpu_list,
rep->cpu_bitmap);
if (ret)
goto out_delete;
return ret;
}
if (use_browser <= 0)
@ -508,11 +508,11 @@ static int __cmd_report(struct perf_report *rep)
ret = perf_report__setup_sample_type(rep);
if (ret)
goto out_delete;
return ret;
ret = perf_session__process_events(session, &rep->tool);
if (ret)
goto out_delete;
return ret;
kernel_map = session->machines.host.vmlinux_maps[MAP__FUNCTION];
kernel_kmap = map__kmap(kernel_map);
@ -547,7 +547,7 @@ static int __cmd_report(struct perf_report *rep)
if (dump_trace) {
perf_session__fprintf_nr_events(session, stdout);
goto out_delete;
return 0;
}
nr_samples = 0;
@ -572,7 +572,7 @@ static int __cmd_report(struct perf_report *rep)
if (nr_samples == 0) {
ui__error("The %s file has no samples!\n", session->filename);
goto out_delete;
return 0;
}
list_for_each_entry(pos, &session->evlist->entries, node)
@ -598,19 +598,6 @@ static int __cmd_report(struct perf_report *rep)
} else
perf_evlist__tty_browse_hists(session->evlist, rep, help);
out_delete:
/*
* Speed up the exit process, for large files this can
* take quite a while.
*
* XXX Enable this when using valgrind or if we ever
* librarize this command.
*
* Also experiment with obstacks to see how much speed
* up we'll get here.
*
* perf_session__delete(session);
*/
return ret;
}
@ -694,6 +681,24 @@ setup:
return 0;
}
int
report_parse_ignore_callees_opt(const struct option *opt __maybe_unused,
const char *arg, int unset __maybe_unused)
{
if (arg) {
int err = regcomp(&ignore_callees_regex, arg, REG_EXTENDED);
if (err) {
char buf[BUFSIZ];
regerror(err, &ignore_callees_regex, buf, sizeof(buf));
pr_err("Invalid --ignore-callees regex: %s\n%s", arg, buf);
return -1;
}
have_ignore_callees = 1;
}
return 0;
}
static int
parse_branch_mode(const struct option *opt __maybe_unused,
const char *str __maybe_unused, int unset)
@ -736,7 +741,6 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
.lost = perf_event__process_lost,
.read = process_read_event,
.attr = perf_event__process_attr,
.event_type = perf_event__process_event_type,
.tracing_data = perf_event__process_tracing_data,
.build_id = perf_event__process_build_id,
.ordered_samples = true,
@ -784,6 +788,9 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
"Default: fractal,0.5,callee", &parse_callchain_opt, callchain_default_opt),
OPT_BOOLEAN('G', "inverted", &report.inverted_callchain,
"alias for inverted call graph"),
OPT_CALLBACK(0, "ignore-callees", NULL, "regex",
"ignore callees of these functions in call graphs",
report_parse_ignore_callees_opt),
OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
"only consider symbols in these dsos"),
OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
@ -853,7 +860,6 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
setup_browser(true);
else {
use_browser = 0;
perf_hpp__column_enable(PERF_HPP__OVERHEAD);
perf_hpp__init();
}
@ -931,14 +937,6 @@ repeat:
if (parent_pattern != default_parent_pattern) {
if (sort_dimension__add("parent") < 0)
goto error;
/*
* Only show the parent fields if we explicitly
* sort that way. If we only use parent machinery
* for filtering, we don't want it.
*/
if (!strstr(sort_order, "parent"))
sort_parent.elide = 1;
}
if (argc) {

View File

@ -1075,7 +1075,7 @@ static int latency_migrate_task_event(struct perf_sched *sched,
if (!atoms) {
if (thread_atoms_insert(sched, migrant))
return -1;
register_pid(sched, migrant->pid, migrant->comm);
register_pid(sched, migrant->tid, migrant->comm);
atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid);
if (!atoms) {
pr_err("migration-event: Internal tree error");
@ -1115,7 +1115,7 @@ static void output_lat_thread(struct perf_sched *sched, struct work_atoms *work_
sched->all_runtime += work_list->total_runtime;
sched->all_count += work_list->nb_atoms;
ret = printf(" %s:%d ", work_list->thread->comm, work_list->thread->pid);
ret = printf(" %s:%d ", work_list->thread->comm, work_list->thread->tid);
for (i = 0; i < 24 - ret; i++)
printf(" ");
@ -1131,9 +1131,9 @@ static void output_lat_thread(struct perf_sched *sched, struct work_atoms *work_
static int pid_cmp(struct work_atoms *l, struct work_atoms *r)
{
if (l->thread->pid < r->thread->pid)
if (l->thread->tid < r->thread->tid)
return -1;
if (l->thread->pid > r->thread->pid)
if (l->thread->tid > r->thread->tid)
return 1;
return 0;
@ -1321,7 +1321,7 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel,
printf("*");
if (sched->curr_thread[cpu]) {
if (sched->curr_thread[cpu]->pid)
if (sched->curr_thread[cpu]->tid)
printf("%2s ", sched->curr_thread[cpu]->shortname);
else
printf(". ");
@ -1332,7 +1332,7 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel,
printf(" %12.6f secs ", (double)timestamp/1e9);
if (new_shortname) {
printf("%s => %s:%d\n",
sched_in->shortname, sched_in->comm, sched_in->pid);
sched_in->shortname, sched_in->comm, sched_in->tid);
} else {
printf("\n");
}
@ -1662,28 +1662,29 @@ static int __cmd_record(int argc, const char **argv)
return cmd_record(i, rec_argv, NULL);
}
static const char default_sort_order[] = "avg, max, switch, runtime";
static struct perf_sched sched = {
.tool = {
.sample = perf_sched__process_tracepoint_sample,
.comm = perf_event__process_comm,
.lost = perf_event__process_lost,
.fork = perf_event__process_fork,
.ordered_samples = true,
},
.cmp_pid = LIST_HEAD_INIT(sched.cmp_pid),
.sort_list = LIST_HEAD_INIT(sched.sort_list),
.start_work_mutex = PTHREAD_MUTEX_INITIALIZER,
.work_done_wait_mutex = PTHREAD_MUTEX_INITIALIZER,
.curr_pid = { [0 ... MAX_CPUS - 1] = -1 },
.sort_order = default_sort_order,
.replay_repeat = 10,
.profile_cpu = -1,
.next_shortname1 = 'A',
.next_shortname2 = '0',
};
int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
{
const char default_sort_order[] = "avg, max, switch, runtime";
struct perf_sched sched = {
.tool = {
.sample = perf_sched__process_tracepoint_sample,
.comm = perf_event__process_comm,
.lost = perf_event__process_lost,
.fork = perf_event__process_fork,
.ordered_samples = true,
},
.cmp_pid = LIST_HEAD_INIT(sched.cmp_pid),
.sort_list = LIST_HEAD_INIT(sched.sort_list),
.start_work_mutex = PTHREAD_MUTEX_INITIALIZER,
.work_done_wait_mutex = PTHREAD_MUTEX_INITIALIZER,
.curr_pid = { [0 ... MAX_CPUS - 1] = -1 },
.sort_order = default_sort_order,
.replay_repeat = 10,
.profile_cpu = -1,
.next_shortname1 = 'A',
.next_shortname2 = '0',
};
const struct option latency_options[] = {
OPT_STRING('s', "sort", &sched.sort_order, "key[,key2...]",
"sort by key(s): runtime, switch, avg, max"),

View File

@ -24,6 +24,7 @@ static u64 last_timestamp;
static u64 nr_unordered;
extern const struct option record_options[];
static bool no_callchain;
static bool latency_format;
static bool system_wide;
static const char *cpu_list;
static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
@ -523,7 +524,6 @@ static struct perf_tool perf_script = {
.exit = perf_event__process_exit,
.fork = perf_event__process_fork,
.attr = perf_event__process_attr,
.event_type = perf_event__process_event_type,
.tracing_data = perf_event__process_tracing_data,
.build_id = perf_event__process_build_id,
.ordered_samples = true,

View File

@ -12,6 +12,8 @@
* of the License.
*/
#include <traceevent/event-parse.h>
#include "builtin.h"
#include "util/util.h"
@ -19,6 +21,7 @@
#include "util/color.h"
#include <linux/list.h>
#include "util/cache.h"
#include "util/evlist.h"
#include "util/evsel.h"
#include <linux/rbtree.h>
#include "util/symbol.h"
@ -328,25 +331,6 @@ struct wakeup_entry {
int success;
};
/*
* trace_flag_type is an enumeration that holds different
* states when a trace occurs. These are:
* IRQS_OFF - interrupts were disabled
* IRQS_NOSUPPORT - arch does not support irqs_disabled_flags
* NEED_RESCED - reschedule is requested
* HARDIRQ - inside an interrupt handler
* SOFTIRQ - inside a softirq handler
*/
enum trace_flag_type {
TRACE_FLAG_IRQS_OFF = 0x01,
TRACE_FLAG_IRQS_NOSUPPORT = 0x02,
TRACE_FLAG_NEED_RESCHED = 0x04,
TRACE_FLAG_HARDIRQ = 0x08,
TRACE_FLAG_SOFTIRQ = 0x10,
};
struct sched_switch {
struct trace_entry te;
char prev_comm[TASK_COMM_LEN];
@ -479,6 +463,8 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te)
}
}
typedef int (*tracepoint_handler)(struct perf_evsel *evsel,
struct perf_sample *sample);
static int process_sample_event(struct perf_tool *tool __maybe_unused,
union perf_event *event __maybe_unused,
@ -486,8 +472,6 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
struct perf_evsel *evsel,
struct machine *machine __maybe_unused)
{
struct trace_entry *te;
if (evsel->attr.sample_type & PERF_SAMPLE_TIME) {
if (!first_time || first_time > sample->time)
first_time = sample->time;
@ -495,69 +479,90 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
last_time = sample->time;
}
te = (void *)sample->raw_data;
if ((evsel->attr.sample_type & PERF_SAMPLE_RAW) && sample->raw_size > 0) {
char *event_str;
#ifdef SUPPORT_OLD_POWER_EVENTS
struct power_entry_old *peo;
peo = (void *)te;
#endif
/*
* FIXME: use evsel, its already mapped from id to perf_evsel,
* remove perf_header__find_event infrastructure bits.
* Mapping all these "power:cpu_idle" strings to the tracepoint
* ID and then just comparing against evsel->attr.config.
*
* e.g.:
*
* if (evsel->attr.config == power_cpu_idle_id)
*/
event_str = perf_header__find_event(te->type);
if (sample->cpu > numcpus)
numcpus = sample->cpu;
if (!event_str)
return 0;
if (sample->cpu > numcpus)
numcpus = sample->cpu;
if (strcmp(event_str, "power:cpu_idle") == 0) {
struct power_processor_entry *ppe = (void *)te;
if (ppe->state == (u32)PWR_EVENT_EXIT)
c_state_end(ppe->cpu_id, sample->time);
else
c_state_start(ppe->cpu_id, sample->time,
ppe->state);
}
else if (strcmp(event_str, "power:cpu_frequency") == 0) {
struct power_processor_entry *ppe = (void *)te;
p_state_change(ppe->cpu_id, sample->time, ppe->state);
}
else if (strcmp(event_str, "sched:sched_wakeup") == 0)
sched_wakeup(sample->cpu, sample->time, sample->pid, te);
else if (strcmp(event_str, "sched:sched_switch") == 0)
sched_switch(sample->cpu, sample->time, te);
#ifdef SUPPORT_OLD_POWER_EVENTS
if (use_old_power_events) {
if (strcmp(event_str, "power:power_start") == 0)
c_state_start(peo->cpu_id, sample->time,
peo->value);
else if (strcmp(event_str, "power:power_end") == 0)
c_state_end(sample->cpu, sample->time);
else if (strcmp(event_str,
"power:power_frequency") == 0)
p_state_change(peo->cpu_id, sample->time,
peo->value);
}
#endif
if (evsel->handler.func != NULL) {
tracepoint_handler f = evsel->handler.func;
return f(evsel, sample);
}
return 0;
}
static int
process_sample_cpu_idle(struct perf_evsel *evsel __maybe_unused,
struct perf_sample *sample)
{
struct power_processor_entry *ppe = sample->raw_data;
if (ppe->state == (u32) PWR_EVENT_EXIT)
c_state_end(ppe->cpu_id, sample->time);
else
c_state_start(ppe->cpu_id, sample->time, ppe->state);
return 0;
}
static int
process_sample_cpu_frequency(struct perf_evsel *evsel __maybe_unused,
struct perf_sample *sample)
{
struct power_processor_entry *ppe = sample->raw_data;
p_state_change(ppe->cpu_id, sample->time, ppe->state);
return 0;
}
static int
process_sample_sched_wakeup(struct perf_evsel *evsel __maybe_unused,
struct perf_sample *sample)
{
struct trace_entry *te = sample->raw_data;
sched_wakeup(sample->cpu, sample->time, sample->pid, te);
return 0;
}
static int
process_sample_sched_switch(struct perf_evsel *evsel __maybe_unused,
struct perf_sample *sample)
{
struct trace_entry *te = sample->raw_data;
sched_switch(sample->cpu, sample->time, te);
return 0;
}
#ifdef SUPPORT_OLD_POWER_EVENTS
static int
process_sample_power_start(struct perf_evsel *evsel __maybe_unused,
struct perf_sample *sample)
{
struct power_entry_old *peo = sample->raw_data;
c_state_start(peo->cpu_id, sample->time, peo->value);
return 0;
}
static int
process_sample_power_end(struct perf_evsel *evsel __maybe_unused,
struct perf_sample *sample)
{
c_state_end(sample->cpu, sample->time);
return 0;
}
static int
process_sample_power_frequency(struct perf_evsel *evsel __maybe_unused,
struct perf_sample *sample)
{
struct power_entry_old *peo = sample->raw_data;
p_state_change(peo->cpu_id, sample->time, peo->value);
return 0;
}
#endif /* SUPPORT_OLD_POWER_EVENTS */
/*
* After the last sample we need to wrap up the current C/P state
* and close out each CPU for these.
@ -974,6 +979,17 @@ static int __cmd_timechart(const char *output_name)
.sample = process_sample_event,
.ordered_samples = true,
};
const struct perf_evsel_str_handler power_tracepoints[] = {
{ "power:cpu_idle", process_sample_cpu_idle },
{ "power:cpu_frequency", process_sample_cpu_frequency },
{ "sched:sched_wakeup", process_sample_sched_wakeup },
{ "sched:sched_switch", process_sample_sched_switch },
#ifdef SUPPORT_OLD_POWER_EVENTS
{ "power:power_start", process_sample_power_start },
{ "power:power_end", process_sample_power_end },
{ "power:power_frequency", process_sample_power_frequency },
#endif
};
struct perf_session *session = perf_session__new(input_name, O_RDONLY,
0, false, &perf_timechart);
int ret = -EINVAL;
@ -984,6 +1000,12 @@ static int __cmd_timechart(const char *output_name)
if (!perf_session__has_traces(session, "timechart record"))
goto out_delete;
if (perf_session__set_tracepoints_handlers(session,
power_tracepoints)) {
pr_err("Initializing session tracepoint handlers failed\n");
goto out_delete;
}
ret = perf_session__process_events(session, &perf_timechart);
if (ret)
goto out_delete;

View File

@ -40,6 +40,7 @@
#include "util/xyarray.h"
#include "util/sort.h"
#include "util/intlist.h"
#include "arch/common.h"
#include "util/debug.h"
@ -772,8 +773,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
sample->callchain) {
err = machine__resolve_callchain(machine, evsel,
al.thread, sample,
&parent);
&parent, &al);
if (err)
return;
}
@ -939,6 +939,12 @@ static int __cmd_top(struct perf_top *top)
if (top->session == NULL)
return -ENOMEM;
if (!objdump_path) {
ret = perf_session_env__lookup_objdump(&top->session->header.env);
if (ret)
goto out_delete;
}
ret = perf_top__setup_sample_type(top);
if (ret)
goto out_delete;
@ -1102,6 +1108,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
OPT_CALLBACK_DEFAULT('G', "call-graph", &top.record_opts,
"mode[,dump_size]", record_callchain_help,
&parse_callchain_opt, "fp"),
OPT_CALLBACK(0, "ignore-callees", NULL, "regex",
"ignore callees of these functions in call graphs",
report_parse_ignore_callees_opt),
OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
"Show a column with the sum of periods"),
OPT_STRING(0, "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
@ -1114,6 +1123,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
"Interleave source code with assembly code (default)"),
OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw,
"Display raw encoding of assembly instructions (default)"),
OPT_STRING(0, "objdump", &objdump_path, "path",
"objdump binary to use for disassembly and annotations"),
OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
"Specify disassembler style (e.g. -M intel for intel syntax)"),
OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"),

View File

@ -1,3 +1,4 @@
#include <traceevent/event-parse.h>
#include "builtin.h"
#include "util/color.h"
#include "util/evlist.h"
@ -5,7 +6,6 @@
#include "util/thread.h"
#include "util/parse-options.h"
#include "util/thread_map.h"
#include "event-parse.h"
#include <libaudit.h>
#include <stdlib.h>
@ -142,7 +142,7 @@ static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thre
printed += fprintf_duration(duration, fp);
if (trace->multiple_threads)
printed += fprintf(fp, "%d ", thread->pid);
printed += fprintf(fp, "%d ", thread->tid);
return printed;
}
@ -593,7 +593,7 @@ static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
color = PERF_COLOR_YELLOW;
printed += color_fprintf(fp, color, "%20s", thread->comm);
printed += fprintf(fp, " - %-5d :%11lu [", thread->pid, ttrace->nr_events);
printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events);
printed += color_fprintf(fp, color, "%5.1f%%", ratio);
printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
}

View File

@ -46,6 +46,8 @@ ifneq ($(obj-perf),)
obj-perf := $(abspath $(obj-perf))/
endif
LIB_INCLUDE := $(srctree)/tools/lib/
# include ARCH specific config
-include $(src-perf)/arch/$(ARCH)/Makefile
@ -121,8 +123,7 @@ endif
CFLAGS += -I$(src-perf)/util
CFLAGS += -I$(src-perf)
CFLAGS += -I$(TRACE_EVENT_DIR)
CFLAGS += -I$(srctree)/tools/lib/
CFLAGS += -I$(LIB_INCLUDE)
CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE

View File

@ -10,14 +10,6 @@
#include "symbol.h"
#include "tests.h"
#define TEST_ASSERT_VAL(text, cond) \
do { \
if (!(cond)) { \
pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
return -1; \
} \
} while (0)
static char *test_file(int size)
{
static char buf_templ[] = "/tmp/test-XXXXXX";

View File

@ -1,6 +1,6 @@
#include <traceevent/event-parse.h>
#include "evsel.h"
#include "tests.h"
#include "event-parse.h"
static int perf_evsel__test_field(struct perf_evsel *evsel, const char *name,
int size, bool should_be_signed)
@ -49,7 +49,7 @@ int test__perf_evsel__tp_sched_test(void)
if (perf_evsel__test_field(evsel, "prev_prio", 4, true))
ret = -1;
if (perf_evsel__test_field(evsel, "prev_state", 8, true))
if (perf_evsel__test_field(evsel, "prev_state", sizeof(long), true))
ret = -1;
if (perf_evsel__test_field(evsel, "next_comm", 16, true))

View File

@ -7,14 +7,6 @@
#include "tests.h"
#include <linux/hw_breakpoint.h>
#define TEST_ASSERT_VAL(text, cond) \
do { \
if (!(cond)) { \
pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
return -1; \
} \
} while (0)
#define PERF_TP_SAMPLE_TYPE (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | \
PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD)
@ -1254,24 +1246,20 @@ static int test_events(struct evlist_test *events, unsigned cnt)
static int test_term(struct terms_test *t)
{
struct list_head *terms;
struct list_head terms;
int ret;
terms = malloc(sizeof(*terms));
if (!terms)
return -ENOMEM;
INIT_LIST_HEAD(&terms);
INIT_LIST_HEAD(terms);
ret = parse_events_terms(terms, t->str);
ret = parse_events_terms(&terms, t->str);
if (ret) {
pr_debug("failed to parse terms '%s', err %d\n",
t->str , ret);
return ret;
}
ret = t->check(terms);
parse_events__free_terms(terms);
ret = t->check(&terms);
parse_events__free_terms(&terms);
return ret;
}

View File

@ -1,6 +1,14 @@
#ifndef TESTS_H
#define TESTS_H
#define TEST_ASSERT_VAL(text, cond) \
do { \
if (!(cond)) { \
pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
return -1; \
} \
} while (0)
enum {
TEST_OK = 0,
TEST_FAIL = -1,

View File

@ -139,11 +139,18 @@ next_pair:
* _really_ have a problem.
*/
s64 skew = sym->end - pair->end;
if (llabs(skew) < page_size)
continue;
if (llabs(skew) >= page_size)
pr_debug("%#" PRIx64 ": diff end addr for %s v: %#" PRIx64 " k: %#" PRIx64 "\n",
sym->start, sym->name, sym->end, pair->end);
/*
* Do not count this as a failure, because we
* could really find a case where it's not
* possible to get proper function end from
* kallsyms.
*/
continue;
pr_debug("%#" PRIx64 ": diff end addr for %s v: %#" PRIx64 " k: %#" PRIx64 "\n",
sym->start, sym->name, sym->end, pair->end);
} else {
struct rb_node *nnd;
detour:

View File

@ -685,8 +685,10 @@ static u64 __hpp_get_##_field(struct hist_entry *he) \
return he->stat._field; \
} \
\
static int hist_browser__hpp_color_##_type(struct perf_hpp *hpp, \
struct hist_entry *he) \
static int \
hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\
struct perf_hpp *hpp, \
struct hist_entry *he) \
{ \
return __hpp__color_fmt(hpp, he, __hpp_get_##_field, _cb); \
}
@ -701,8 +703,6 @@ __HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us, NULL)
void hist_browser__init_hpp(void)
{
perf_hpp__column_enable(PERF_HPP__OVERHEAD);
perf_hpp__init();
perf_hpp__format[PERF_HPP__OVERHEAD].color =
@ -762,9 +762,9 @@ static int hist_browser__show_entry(struct hist_browser *browser,
first = false;
if (fmt->color) {
width -= fmt->color(&hpp, entry);
width -= fmt->color(fmt, &hpp, entry);
} else {
width -= fmt->entry(&hpp, entry);
width -= fmt->entry(fmt, &hpp, entry);
slsmg_printf("%s", s);
}
}
@ -1256,7 +1256,7 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size,
printed += scnprintf(bf + printed, size - printed,
", Thread: %s(%d)",
(thread->comm_set ? thread->comm : ""),
thread->pid);
thread->tid);
if (dso)
printed += scnprintf(bf + printed, size - printed,
", DSO: %s", dso->short_name);
@ -1579,7 +1579,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
(browser->hists->thread_filter ? "out of" : "into"),
(thread->comm_set ? thread->comm : ""),
thread->pid) > 0)
thread->tid) > 0)
zoom_thread = nr_options++;
if (dso != NULL &&
@ -1702,7 +1702,7 @@ zoom_out_thread:
} else {
ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
thread->comm_set ? thread->comm : "",
thread->pid);
thread->tid);
browser->hists->thread_filter = thread;
sort_thread.elide = true;
pstack__push(fstack, &browser->hists->thread_filter);

View File

@ -91,7 +91,8 @@ static u64 he_get_##_field(struct hist_entry *he) \
return he->stat._field; \
} \
\
static int perf_gtk__hpp_color_##_type(struct perf_hpp *hpp, \
static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
struct perf_hpp *hpp, \
struct hist_entry *he) \
{ \
return __hpp__color_fmt(hpp, he, he_get_##_field); \
@ -124,6 +125,81 @@ void perf_gtk__init_hpp(void)
perf_gtk__hpp_color_overhead_guest_us;
}
static void callchain_list__sym_name(struct callchain_list *cl,
char *bf, size_t bfsize)
{
if (cl->ms.sym)
scnprintf(bf, bfsize, "%s", cl->ms.sym->name);
else
scnprintf(bf, bfsize, "%#" PRIx64, cl->ip);
}
static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store,
GtkTreeIter *parent, int col, u64 total)
{
struct rb_node *nd;
bool has_single_node = (rb_first(root) == rb_last(root));
for (nd = rb_first(root); nd; nd = rb_next(nd)) {
struct callchain_node *node;
struct callchain_list *chain;
GtkTreeIter iter, new_parent;
bool need_new_parent;
double percent;
u64 hits, child_total;
node = rb_entry(nd, struct callchain_node, rb_node);
hits = callchain_cumul_hits(node);
percent = 100.0 * hits / total;
new_parent = *parent;
need_new_parent = !has_single_node && (node->val_nr > 1);
list_for_each_entry(chain, &node->val, list) {
char buf[128];
gtk_tree_store_append(store, &iter, &new_parent);
scnprintf(buf, sizeof(buf), "%5.2f%%", percent);
gtk_tree_store_set(store, &iter, 0, buf, -1);
callchain_list__sym_name(chain, buf, sizeof(buf));
gtk_tree_store_set(store, &iter, col, buf, -1);
if (need_new_parent) {
/*
* Only show the top-most symbol in a callchain
* if it's not the only callchain.
*/
new_parent = iter;
need_new_parent = false;
}
}
if (callchain_param.mode == CHAIN_GRAPH_REL)
child_total = node->children_hit;
else
child_total = total;
/* Now 'iter' contains info of the last callchain_list */
perf_gtk__add_callchain(&node->rb_root, store, &iter, col,
child_total);
}
}
static void on_row_activated(GtkTreeView *view, GtkTreePath *path,
GtkTreeViewColumn *col __maybe_unused,
gpointer user_data __maybe_unused)
{
bool expanded = gtk_tree_view_row_expanded(view, path);
if (expanded)
gtk_tree_view_collapse_row(view, path);
else
gtk_tree_view_expand_row(view, path, FALSE);
}
static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
float min_pcnt)
{
@ -131,10 +207,11 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
GType col_types[MAX_COLUMNS];
GtkCellRenderer *renderer;
struct sort_entry *se;
GtkListStore *store;
GtkTreeStore *store;
struct rb_node *nd;
GtkWidget *view;
int col_idx;
int sym_col = -1;
int nr_cols;
char s[512];
@ -153,10 +230,13 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
if (se->elide)
continue;
if (se == &sort_sym)
sym_col = nr_cols;
col_types[nr_cols++] = G_TYPE_STRING;
}
store = gtk_list_store_newv(nr_cols, col_types);
store = gtk_tree_store_newv(nr_cols, col_types);
view = gtk_tree_view_new();
@ -165,7 +245,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
col_idx = 0;
perf_hpp__for_each_format(fmt) {
fmt->header(&hpp);
fmt->header(fmt, &hpp);
gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
-1, ltrim(s),
@ -183,6 +263,18 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
col_idx++, NULL);
}
for (col_idx = 0; col_idx < nr_cols; col_idx++) {
GtkTreeViewColumn *column;
column = gtk_tree_view_get_column(GTK_TREE_VIEW(view), col_idx);
gtk_tree_view_column_set_resizable(column, TRUE);
if (col_idx == sym_col) {
gtk_tree_view_set_expander_column(GTK_TREE_VIEW(view),
column);
}
}
gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
g_object_unref(GTK_TREE_MODEL(store));
@ -199,17 +291,17 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
if (percent < min_pcnt)
continue;
gtk_list_store_append(store, &iter);
gtk_tree_store_append(store, &iter, NULL);
col_idx = 0;
perf_hpp__for_each_format(fmt) {
if (fmt->color)
fmt->color(&hpp, h);
fmt->color(fmt, &hpp, h);
else
fmt->entry(&hpp, h);
fmt->entry(fmt, &hpp, h);
gtk_list_store_set(store, &iter, col_idx++, s, -1);
gtk_tree_store_set(store, &iter, col_idx++, s, -1);
}
list_for_each_entry(se, &hist_entry__sort_list, list) {
@ -219,10 +311,26 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
se->se_snprintf(h, s, ARRAY_SIZE(s),
hists__col_len(hists, se->se_width_idx));
gtk_list_store_set(store, &iter, col_idx++, s, -1);
gtk_tree_store_set(store, &iter, col_idx++, s, -1);
}
if (symbol_conf.use_callchain && sort__has_sym) {
u64 total;
if (callchain_param.mode == CHAIN_GRAPH_REL)
total = h->stat.period;
else
total = hists->stats.total_period;
perf_gtk__add_callchain(&h->sorted_chain, store, &iter,
sym_col, total);
}
}
gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(view), TRUE);
g_signal_connect(view, "row-activated",
G_CALLBACK(on_row_activated), NULL);
gtk_container_add(GTK_CONTAINER(window), view);
}

View File

@ -1,4 +1,5 @@
#include <math.h>
#include <linux/compiler.h>
#include "../util/hist.h"
#include "../util/util.h"
@ -79,7 +80,8 @@ static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
}
#define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \
static int hpp__header_##_type(struct perf_hpp *hpp) \
static int hpp__header_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
struct perf_hpp *hpp) \
{ \
int len = _min_width; \
\
@ -92,7 +94,8 @@ static int hpp__header_##_type(struct perf_hpp *hpp) \
}
#define __HPP_WIDTH_FN(_type, _min_width, _unit_width) \
static int hpp__width_##_type(struct perf_hpp *hpp __maybe_unused) \
static int hpp__width_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
struct perf_hpp *hpp __maybe_unused) \
{ \
int len = _min_width; \
\
@ -110,14 +113,16 @@ static u64 he_get_##_field(struct hist_entry *he) \
return he->stat._field; \
} \
\
static int hpp__color_##_type(struct perf_hpp *hpp, struct hist_entry *he) \
static int hpp__color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
struct perf_hpp *hpp, struct hist_entry *he) \
{ \
return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%", \
(hpp_snprint_fn)percent_color_snprintf, true); \
}
#define __HPP_ENTRY_PERCENT_FN(_type, _field) \
static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he) \
static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused, \
struct perf_hpp *hpp, struct hist_entry *he) \
{ \
const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%"; \
return __hpp__fmt(hpp, he, he_get_##_field, fmt, \
@ -130,7 +135,8 @@ static u64 he_get_raw_##_field(struct hist_entry *he) \
return he->stat._field; \
} \
\
static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he) \
static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused, \
struct perf_hpp *hpp, struct hist_entry *he) \
{ \
const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64; \
return __hpp__fmt(hpp, he, he_get_raw_##_field, fmt, scnprintf, false); \
@ -157,196 +163,6 @@ HPP_PERCENT_FNS(overhead_guest_us, "guest usr", period_guest_us, 9, 8)
HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12)
HPP_RAW_FNS(period, "Period", period, 12, 12)
static int hpp__header_baseline(struct perf_hpp *hpp)
{
return scnprintf(hpp->buf, hpp->size, "Baseline");
}
static int hpp__width_baseline(struct perf_hpp *hpp __maybe_unused)
{
return 8;
}
static double baseline_percent(struct hist_entry *he)
{
struct hist_entry *pair = hist_entry__next_pair(he);
struct hists *pair_hists = pair ? pair->hists : NULL;
double percent = 0.0;
if (pair) {
u64 total_period = pair_hists->stats.total_period;
u64 base_period = pair->stat.period;
percent = 100.0 * base_period / total_period;
}
return percent;
}
static int hpp__color_baseline(struct perf_hpp *hpp, struct hist_entry *he)
{
double percent = baseline_percent(he);
if (hist_entry__has_pairs(he) || symbol_conf.field_sep)
return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent);
else
return scnprintf(hpp->buf, hpp->size, " ");
}
static int hpp__entry_baseline(struct perf_hpp *hpp, struct hist_entry *he)
{
double percent = baseline_percent(he);
const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%";
if (hist_entry__has_pairs(he) || symbol_conf.field_sep)
return scnprintf(hpp->buf, hpp->size, fmt, percent);
else
return scnprintf(hpp->buf, hpp->size, " ");
}
static int hpp__header_period_baseline(struct perf_hpp *hpp)
{
const char *fmt = symbol_conf.field_sep ? "%s" : "%12s";
return scnprintf(hpp->buf, hpp->size, fmt, "Period Base");
}
static int hpp__width_period_baseline(struct perf_hpp *hpp __maybe_unused)
{
return 12;
}
static int hpp__entry_period_baseline(struct perf_hpp *hpp, struct hist_entry *he)
{
struct hist_entry *pair = hist_entry__next_pair(he);
u64 period = pair ? pair->stat.period : 0;
const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%12" PRIu64;
return scnprintf(hpp->buf, hpp->size, fmt, period);
}
static int hpp__header_delta(struct perf_hpp *hpp)
{
const char *fmt = symbol_conf.field_sep ? "%s" : "%7s";
return scnprintf(hpp->buf, hpp->size, fmt, "Delta");
}
static int hpp__width_delta(struct perf_hpp *hpp __maybe_unused)
{
return 7;
}
static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he)
{
struct hist_entry *pair = hist_entry__next_pair(he);
const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s";
char buf[32] = " ";
double diff = 0.0;
if (pair) {
if (he->diff.computed)
diff = he->diff.period_ratio_delta;
else
diff = perf_diff__compute_delta(he, pair);
} else
diff = perf_diff__period_percent(he, he->stat.period);
if (fabs(diff) >= 0.01)
scnprintf(buf, sizeof(buf), "%+4.2F%%", diff);
return scnprintf(hpp->buf, hpp->size, fmt, buf);
}
static int hpp__header_ratio(struct perf_hpp *hpp)
{
const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
return scnprintf(hpp->buf, hpp->size, fmt, "Ratio");
}
static int hpp__width_ratio(struct perf_hpp *hpp __maybe_unused)
{
return 14;
}
static int hpp__entry_ratio(struct perf_hpp *hpp, struct hist_entry *he)
{
struct hist_entry *pair = hist_entry__next_pair(he);
const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
char buf[32] = " ";
double ratio = 0.0;
if (pair) {
if (he->diff.computed)
ratio = he->diff.period_ratio;
else
ratio = perf_diff__compute_ratio(he, pair);
}
if (ratio > 0.0)
scnprintf(buf, sizeof(buf), "%+14.6F", ratio);
return scnprintf(hpp->buf, hpp->size, fmt, buf);
}
static int hpp__header_wdiff(struct perf_hpp *hpp)
{
const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
return scnprintf(hpp->buf, hpp->size, fmt, "Weighted diff");
}
static int hpp__width_wdiff(struct perf_hpp *hpp __maybe_unused)
{
return 14;
}
static int hpp__entry_wdiff(struct perf_hpp *hpp, struct hist_entry *he)
{
struct hist_entry *pair = hist_entry__next_pair(he);
const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
char buf[32] = " ";
s64 wdiff = 0;
if (pair) {
if (he->diff.computed)
wdiff = he->diff.wdiff;
else
wdiff = perf_diff__compute_wdiff(he, pair);
}
if (wdiff != 0)
scnprintf(buf, sizeof(buf), "%14ld", wdiff);
return scnprintf(hpp->buf, hpp->size, fmt, buf);
}
static int hpp__header_formula(struct perf_hpp *hpp)
{
const char *fmt = symbol_conf.field_sep ? "%s" : "%70s";
return scnprintf(hpp->buf, hpp->size, fmt, "Formula");
}
static int hpp__width_formula(struct perf_hpp *hpp __maybe_unused)
{
return 70;
}
static int hpp__entry_formula(struct perf_hpp *hpp, struct hist_entry *he)
{
struct hist_entry *pair = hist_entry__next_pair(he);
const char *fmt = symbol_conf.field_sep ? "%s" : "%-70s";
char buf[96] = " ";
if (pair)
perf_diff__formula(he, pair, buf, sizeof(buf));
return scnprintf(hpp->buf, hpp->size, fmt, buf);
}
#define HPP__COLOR_PRINT_FNS(_name) \
{ \
.header = hpp__header_ ## _name, \
@ -363,19 +179,13 @@ static int hpp__entry_formula(struct perf_hpp *hpp, struct hist_entry *he)
}
struct perf_hpp_fmt perf_hpp__format[] = {
HPP__COLOR_PRINT_FNS(baseline),
HPP__COLOR_PRINT_FNS(overhead),
HPP__COLOR_PRINT_FNS(overhead_sys),
HPP__COLOR_PRINT_FNS(overhead_us),
HPP__COLOR_PRINT_FNS(overhead_guest_sys),
HPP__COLOR_PRINT_FNS(overhead_guest_us),
HPP__PRINT_FNS(samples),
HPP__PRINT_FNS(period),
HPP__PRINT_FNS(period_baseline),
HPP__PRINT_FNS(delta),
HPP__PRINT_FNS(ratio),
HPP__PRINT_FNS(wdiff),
HPP__PRINT_FNS(formula)
HPP__PRINT_FNS(period)
};
LIST_HEAD(perf_hpp__list);
@ -396,6 +206,8 @@ LIST_HEAD(perf_hpp__list);
void perf_hpp__init(void)
{
perf_hpp__column_enable(PERF_HPP__OVERHEAD);
if (symbol_conf.show_cpu_utilization) {
perf_hpp__column_enable(PERF_HPP__OVERHEAD_SYS);
perf_hpp__column_enable(PERF_HPP__OVERHEAD_US);
@ -424,46 +236,6 @@ void perf_hpp__column_enable(unsigned col)
perf_hpp__column_register(&perf_hpp__format[col]);
}
static inline void advance_hpp(struct perf_hpp *hpp, int inc)
{
hpp->buf += inc;
hpp->size -= inc;
}
int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he,
bool color)
{
const char *sep = symbol_conf.field_sep;
struct perf_hpp_fmt *fmt;
char *start = hpp->buf;
int ret;
bool first = true;
if (symbol_conf.exclude_other && !he->parent)
return 0;
perf_hpp__for_each_format(fmt) {
/*
* If there's no field_sep, we still need
* to display initial ' '.
*/
if (!sep || !first) {
ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " ");
advance_hpp(hpp, ret);
} else
first = false;
if (color && fmt->color)
ret = fmt->color(hpp, he);
else
ret = fmt->entry(hpp, he);
advance_hpp(hpp, ret);
}
return hpp->buf - start;
}
int hist_entry__sort_snprintf(struct hist_entry *he, char *s, size_t size,
struct hists *hists)
{
@ -499,7 +271,7 @@ unsigned int hists__sort_list_width(struct hists *hists)
if (i)
ret += 2;
ret += fmt->width(&dummy_hpp);
ret += fmt->width(fmt, &dummy_hpp);
}
list_for_each_entry(se, &hist_entry__sort_list, list)

View File

@ -30,7 +30,6 @@ void setup_browser(bool fallback_to_pager)
if (fallback_to_pager)
setup_pager();
perf_hpp__column_enable(PERF_HPP__OVERHEAD);
perf_hpp__init();
break;
}

View File

@ -308,6 +308,47 @@ static size_t hist_entry__callchain_fprintf(struct hist_entry *he,
return hist_entry_callchain__fprintf(he, total_period, left_margin, fp);
}
static inline void advance_hpp(struct perf_hpp *hpp, int inc)
{
hpp->buf += inc;
hpp->size -= inc;
}
static int hist_entry__period_snprintf(struct perf_hpp *hpp,
struct hist_entry *he,
bool color)
{
const char *sep = symbol_conf.field_sep;
struct perf_hpp_fmt *fmt;
char *start = hpp->buf;
int ret;
bool first = true;
if (symbol_conf.exclude_other && !he->parent)
return 0;
perf_hpp__for_each_format(fmt) {
/*
* If there's no field_sep, we still need
* to display initial ' '.
*/
if (!sep || !first) {
ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " ");
advance_hpp(hpp, ret);
} else
first = false;
if (color && fmt->color)
ret = fmt->color(fmt, hpp, he);
else
ret = fmt->entry(fmt, hpp, he);
advance_hpp(hpp, ret);
}
return hpp->buf - start;
}
static int hist_entry__fprintf(struct hist_entry *he, size_t size,
struct hists *hists, FILE *fp)
{
@ -365,7 +406,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
else
first = false;
fmt->header(&dummy_hpp);
fmt->header(fmt, &dummy_hpp);
fprintf(fp, "%s", bf);
}
@ -410,7 +451,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
else
first = false;
width = fmt->width(&dummy_hpp);
width = fmt->width(fmt, &dummy_hpp);
for (i = 0; i < width; i++)
fprintf(fp, ".");
}

View File

@ -41,7 +41,7 @@ static inline int cpu_map__nr(const struct cpu_map *map)
return map ? map->nr : 1;
}
static inline bool cpu_map__all(const struct cpu_map *map)
static inline bool cpu_map__empty(const struct cpu_map *map)
{
return map ? map->map[0] == -1 : true;
}

View File

@ -686,7 +686,7 @@ int perf_event__preprocess_sample(const union perf_event *event,
!strlist__has_entry(symbol_conf.comm_list, thread->comm))
goto out_filtered;
dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
dump_printf(" ... thread: %s:%d\n", thread->comm, thread->tid);
/*
* Have we already created the kernel maps for this machine?
*

View File

@ -116,7 +116,7 @@ struct build_id_event {
enum perf_user_event_type { /* above any possible kernel type */
PERF_RECORD_USER_TYPE_START = 64,
PERF_RECORD_HEADER_ATTR = 64,
PERF_RECORD_HEADER_EVENT_TYPE = 65,
PERF_RECORD_HEADER_EVENT_TYPE = 65, /* depreceated */
PERF_RECORD_HEADER_TRACING_DATA = 66,
PERF_RECORD_HEADER_BUILD_ID = 67,
PERF_RECORD_FINISHED_ROUND = 68,

View File

@ -403,16 +403,20 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
return event;
}
static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx)
{
if (evlist->mmap[idx].base != NULL) {
munmap(evlist->mmap[idx].base, evlist->mmap_len);
evlist->mmap[idx].base = NULL;
}
}
void perf_evlist__munmap(struct perf_evlist *evlist)
{
int i;
for (i = 0; i < evlist->nr_mmaps; i++) {
if (evlist->mmap[i].base != NULL) {
munmap(evlist->mmap[i].base, evlist->mmap_len);
evlist->mmap[i].base = NULL;
}
}
for (i = 0; i < evlist->nr_mmaps; i++)
__perf_evlist__munmap(evlist, i);
free(evlist->mmap);
evlist->mmap = NULL;
@ -421,7 +425,7 @@ void perf_evlist__munmap(struct perf_evlist *evlist)
static int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
{
evlist->nr_mmaps = cpu_map__nr(evlist->cpus);
if (cpu_map__all(evlist->cpus))
if (cpu_map__empty(evlist->cpus))
evlist->nr_mmaps = thread_map__nr(evlist->threads);
evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap));
return evlist->mmap != NULL ? 0 : -ENOMEM;
@ -477,12 +481,8 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int m
return 0;
out_unmap:
for (cpu = 0; cpu < nr_cpus; cpu++) {
if (evlist->mmap[cpu].base != NULL) {
munmap(evlist->mmap[cpu].base, evlist->mmap_len);
evlist->mmap[cpu].base = NULL;
}
}
for (cpu = 0; cpu < nr_cpus; cpu++)
__perf_evlist__munmap(evlist, cpu);
return -1;
}
@ -517,12 +517,8 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, in
return 0;
out_unmap:
for (thread = 0; thread < nr_threads; thread++) {
if (evlist->mmap[thread].base != NULL) {
munmap(evlist->mmap[thread].base, evlist->mmap_len);
evlist->mmap[thread].base = NULL;
}
}
for (thread = 0; thread < nr_threads; thread++)
__perf_evlist__munmap(evlist, thread);
return -1;
}
@ -573,7 +569,7 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
return -ENOMEM;
}
if (cpu_map__all(cpus))
if (cpu_map__empty(cpus))
return perf_evlist__mmap_per_thread(evlist, prot, mask);
return perf_evlist__mmap_per_cpu(evlist, prot, mask);
@ -838,7 +834,7 @@ out_close_ready_pipe:
int perf_evlist__start_workload(struct perf_evlist *evlist)
{
if (evlist->workload.cork_fd > 0) {
char bf;
char bf = 0;
int ret;
/*
* Remove the cork, let it rip!

View File

@ -9,17 +9,17 @@
#include <byteswap.h>
#include <linux/bitops.h>
#include "asm/bug.h"
#include <lk/debugfs.h>
#include "event-parse.h"
#include <traceevent/event-parse.h>
#include <linux/hw_breakpoint.h>
#include <linux/perf_event.h>
#include "asm/bug.h"
#include "evsel.h"
#include "evlist.h"
#include "util.h"
#include "cpumap.h"
#include "thread_map.h"
#include "target.h"
#include <linux/hw_breakpoint.h>
#include <linux/perf_event.h>
#include "perf_regs.h"
static struct {

View File

@ -25,41 +25,9 @@
static bool no_buildid_cache = false;
static int trace_event_count;
static struct perf_trace_event_type *trace_events;
static u32 header_argc;
static const char **header_argv;
int perf_header__push_event(u64 id, const char *name)
{
struct perf_trace_event_type *nevents;
if (strlen(name) > MAX_EVENT_NAME)
pr_warning("Event %s will be truncated\n", name);
nevents = realloc(trace_events, (trace_event_count + 1) * sizeof(*trace_events));
if (nevents == NULL)
return -ENOMEM;
trace_events = nevents;
memset(&trace_events[trace_event_count], 0, sizeof(struct perf_trace_event_type));
trace_events[trace_event_count].event_id = id;
strncpy(trace_events[trace_event_count].name, name, MAX_EVENT_NAME - 1);
trace_event_count++;
return 0;
}
char *perf_header__find_event(u64 id)
{
int i;
for (i = 0 ; i < trace_event_count; i++) {
if (trace_events[i].event_id == id)
return trace_events[i].name;
}
return NULL;
}
/*
* magic2 = "PERFILE2"
* must be a numerical value to let the endianness
@ -2257,7 +2225,7 @@ static int perf_header__adds_write(struct perf_header *header,
sec_size = sizeof(*feat_sec) * nr_sections;
sec_start = header->data_offset + header->data_size;
sec_start = header->feat_offset;
lseek(fd, sec_start + sec_size, SEEK_SET);
for_each_set_bit(feat, header->adds_features, HEADER_FEAT_BITS) {
@ -2304,6 +2272,7 @@ int perf_session__write_header(struct perf_session *session,
struct perf_file_attr f_attr;
struct perf_header *header = &session->header;
struct perf_evsel *evsel;
u64 attr_offset;
int err;
lseek(fd, sizeof(f_header), SEEK_SET);
@ -2317,7 +2286,7 @@ int perf_session__write_header(struct perf_session *session,
}
}
header->attr_offset = lseek(fd, 0, SEEK_CUR);
attr_offset = lseek(fd, 0, SEEK_CUR);
list_for_each_entry(evsel, &evlist->entries, node) {
f_attr = (struct perf_file_attr){
@ -2334,17 +2303,8 @@ int perf_session__write_header(struct perf_session *session,
}
}
header->event_offset = lseek(fd, 0, SEEK_CUR);
header->event_size = trace_event_count * sizeof(struct perf_trace_event_type);
if (trace_events) {
err = do_write(fd, trace_events, header->event_size);
if (err < 0) {
pr_debug("failed to write perf header events\n");
return err;
}
}
header->data_offset = lseek(fd, 0, SEEK_CUR);
header->feat_offset = header->data_offset + header->data_size;
if (at_exit) {
err = perf_header__adds_write(header, evlist, fd);
@ -2357,17 +2317,14 @@ int perf_session__write_header(struct perf_session *session,
.size = sizeof(f_header),
.attr_size = sizeof(f_attr),
.attrs = {
.offset = header->attr_offset,
.offset = attr_offset,
.size = evlist->nr_entries * sizeof(f_attr),
},
.data = {
.offset = header->data_offset,
.size = header->data_size,
},
.event_types = {
.offset = header->event_offset,
.size = header->event_size,
},
/* event_types is ignored, store zeros */
};
memcpy(&f_header.adds_features, &header->adds_features, sizeof(header->adds_features));
@ -2417,7 +2374,7 @@ int perf_header__process_sections(struct perf_header *header, int fd,
sec_size = sizeof(*feat_sec) * nr_sections;
lseek(fd, header->data_offset + header->data_size, SEEK_SET);
lseek(fd, header->feat_offset, SEEK_SET);
err = perf_header__getbuffer64(header, fd, feat_sec, sec_size);
if (err < 0)
@ -2523,6 +2480,7 @@ static int check_magic_endian(u64 magic, uint64_t hdr_sz,
/* check for legacy format */
ret = memcmp(&magic, __perf_magic1, sizeof(magic));
if (ret == 0) {
ph->version = PERF_HEADER_VERSION_1;
pr_debug("legacy perf.data format\n");
if (is_pipe)
return try_all_pipe_abis(hdr_sz, ph);
@ -2544,6 +2502,7 @@ static int check_magic_endian(u64 magic, uint64_t hdr_sz,
return -1;
ph->needs_swap = true;
ph->version = PERF_HEADER_VERSION_2;
return 0;
}
@ -2614,10 +2573,9 @@ int perf_file_header__read(struct perf_file_header *header,
memcpy(&ph->adds_features, &header->adds_features,
sizeof(ph->adds_features));
ph->event_offset = header->event_types.offset;
ph->event_size = header->event_types.size;
ph->data_offset = header->data.offset;
ph->data_size = header->data.size;
ph->feat_offset = header->data.offset + header->data.size;
return 0;
}
@ -2666,19 +2624,17 @@ static int perf_file_header__read_pipe(struct perf_pipe_file_header *header,
return 0;
}
static int perf_header__read_pipe(struct perf_session *session, int fd)
static int perf_header__read_pipe(struct perf_session *session)
{
struct perf_header *header = &session->header;
struct perf_pipe_file_header f_header;
if (perf_file_header__read_pipe(&f_header, header, fd,
if (perf_file_header__read_pipe(&f_header, header, session->fd,
session->repipe) < 0) {
pr_debug("incompatible file format\n");
return -EINVAL;
}
session->fd = fd;
return 0;
}
@ -2772,20 +2728,21 @@ static int perf_evlist__prepare_tracepoint_events(struct perf_evlist *evlist,
return 0;
}
int perf_session__read_header(struct perf_session *session, int fd)
int perf_session__read_header(struct perf_session *session)
{
struct perf_header *header = &session->header;
struct perf_file_header f_header;
struct perf_file_attr f_attr;
u64 f_id;
int nr_attrs, nr_ids, i, j;
int fd = session->fd;
session->evlist = perf_evlist__new();
if (session->evlist == NULL)
return -ENOMEM;
if (session->fd_pipe)
return perf_header__read_pipe(session, fd);
return perf_header__read_pipe(session);
if (perf_file_header__read(&f_header, header, fd) < 0)
return -EINVAL;
@ -2839,22 +2796,9 @@ int perf_session__read_header(struct perf_session *session, int fd)
symbol_conf.nr_events = nr_attrs;
if (f_header.event_types.size) {
lseek(fd, f_header.event_types.offset, SEEK_SET);
trace_events = malloc(f_header.event_types.size);
if (trace_events == NULL)
return -ENOMEM;
if (perf_header__getbuffer64(header, fd, trace_events,
f_header.event_types.size))
goto out_errno;
trace_event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type);
}
perf_header__process_sections(header, fd, &session->pevent,
perf_file_section__process);
lseek(fd, header->data_offset, SEEK_SET);
if (perf_evlist__prepare_tracepoint_events(session->evlist,
session->pevent))
goto out_delete_evlist;
@ -2922,7 +2866,8 @@ int perf_event__synthesize_attrs(struct perf_tool *tool,
return err;
}
int perf_event__process_attr(union perf_event *event,
int perf_event__process_attr(struct perf_tool *tool __maybe_unused,
union perf_event *event,
struct perf_evlist **pevlist)
{
u32 i, ids, n_ids;
@ -2961,64 +2906,6 @@ int perf_event__process_attr(union perf_event *event,
return 0;
}
int perf_event__synthesize_event_type(struct perf_tool *tool,
u64 event_id, char *name,
perf_event__handler_t process,
struct machine *machine)
{
union perf_event ev;
size_t size = 0;
int err = 0;
memset(&ev, 0, sizeof(ev));
ev.event_type.event_type.event_id = event_id;
memset(ev.event_type.event_type.name, 0, MAX_EVENT_NAME);
strncpy(ev.event_type.event_type.name, name, MAX_EVENT_NAME - 1);
ev.event_type.header.type = PERF_RECORD_HEADER_EVENT_TYPE;
size = strlen(ev.event_type.event_type.name);
size = PERF_ALIGN(size, sizeof(u64));
ev.event_type.header.size = sizeof(ev.event_type) -
(sizeof(ev.event_type.event_type.name) - size);
err = process(tool, &ev, NULL, machine);
return err;
}
int perf_event__synthesize_event_types(struct perf_tool *tool,
perf_event__handler_t process,
struct machine *machine)
{
struct perf_trace_event_type *type;
int i, err = 0;
for (i = 0; i < trace_event_count; i++) {
type = &trace_events[i];
err = perf_event__synthesize_event_type(tool, type->event_id,
type->name, process,
machine);
if (err) {
pr_debug("failed to create perf header event type\n");
return err;
}
}
return err;
}
int perf_event__process_event_type(struct perf_tool *tool __maybe_unused,
union perf_event *event)
{
if (perf_header__push_event(event->event_type.event_type.event_id,
event->event_type.event_type.name) < 0)
return -ENOMEM;
return 0;
}
int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd,
struct perf_evlist *evlist,
perf_event__handler_t process)
@ -3065,7 +2952,8 @@ int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd,
return aligned_size;
}
int perf_event__process_tracing_data(union perf_event *event,
int perf_event__process_tracing_data(struct perf_tool *tool __maybe_unused,
union perf_event *event,
struct perf_session *session)
{
ssize_t size_read, padding, size = event->tracing_data.size;

View File

@ -34,6 +34,11 @@ enum {
HEADER_FEAT_BITS = 256,
};
enum perf_header_version {
PERF_HEADER_VERSION_1,
PERF_HEADER_VERSION_2,
};
struct perf_file_section {
u64 offset;
u64 size;
@ -45,6 +50,7 @@ struct perf_file_header {
u64 attr_size;
struct perf_file_section attrs;
struct perf_file_section data;
/* event_types is ignored */
struct perf_file_section event_types;
DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
};
@ -84,28 +90,24 @@ struct perf_session_env {
};
struct perf_header {
bool needs_swap;
s64 attr_offset;
u64 data_offset;
u64 data_size;
u64 event_offset;
u64 event_size;
enum perf_header_version version;
bool needs_swap;
u64 data_offset;
u64 data_size;
u64 feat_offset;
DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
struct perf_session_env env;
struct perf_session_env env;
};
struct perf_evlist;
struct perf_session;
int perf_session__read_header(struct perf_session *session, int fd);
int perf_session__read_header(struct perf_session *session);
int perf_session__write_header(struct perf_session *session,
struct perf_evlist *evlist,
int fd, bool at_exit);
int perf_header__write_pipe(int fd);
int perf_header__push_event(u64 id, const char *name);
char *perf_header__find_event(u64 id);
void perf_header__set_feat(struct perf_header *header, int feat);
void perf_header__clear_feat(struct perf_header *header, int feat);
bool perf_header__has_feat(const struct perf_header *header, int feat);
@ -130,22 +132,14 @@ int perf_event__synthesize_attr(struct perf_tool *tool,
int perf_event__synthesize_attrs(struct perf_tool *tool,
struct perf_session *session,
perf_event__handler_t process);
int perf_event__process_attr(union perf_event *event, struct perf_evlist **pevlist);
int perf_event__synthesize_event_type(struct perf_tool *tool,
u64 event_id, char *name,
perf_event__handler_t process,
struct machine *machine);
int perf_event__synthesize_event_types(struct perf_tool *tool,
perf_event__handler_t process,
struct machine *machine);
int perf_event__process_event_type(struct perf_tool *tool,
union perf_event *event);
int perf_event__process_attr(struct perf_tool *tool, union perf_event *event,
struct perf_evlist **pevlist);
int perf_event__synthesize_tracing_data(struct perf_tool *tool,
int fd, struct perf_evlist *evlist,
perf_event__handler_t process);
int perf_event__process_tracing_data(union perf_event *event,
int perf_event__process_tracing_data(struct perf_tool *tool,
union perf_event *event,
struct perf_session *session);
int perf_event__synthesize_build_id(struct perf_tool *tool,

View File

@ -912,6 +912,7 @@ static struct hist_entry *hists__add_dummy_entry(struct hists *hists,
rb_link_node(&he->rb_node_in, parent, p);
rb_insert_color(&he->rb_node_in, root);
hists__inc_nr_entries(hists, he);
he->dummy = true;
}
out:
return he;

View File

@ -141,10 +141,12 @@ struct perf_hpp {
};
struct perf_hpp_fmt {
int (*header)(struct perf_hpp *hpp);
int (*width)(struct perf_hpp *hpp);
int (*color)(struct perf_hpp *hpp, struct hist_entry *he);
int (*entry)(struct perf_hpp *hpp, struct hist_entry *he);
int (*header)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp);
int (*width)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp);
int (*color)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
struct hist_entry *he);
int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
struct hist_entry *he);
struct list_head list;
};
@ -157,7 +159,7 @@ extern struct list_head perf_hpp__list;
extern struct perf_hpp_fmt perf_hpp__format[];
enum {
PERF_HPP__BASELINE,
/* Matches perf_hpp__format array. */
PERF_HPP__OVERHEAD,
PERF_HPP__OVERHEAD_SYS,
PERF_HPP__OVERHEAD_US,
@ -165,11 +167,6 @@ enum {
PERF_HPP__OVERHEAD_GUEST_US,
PERF_HPP__SAMPLES,
PERF_HPP__PERIOD,
PERF_HPP__PERIOD_BASELINE,
PERF_HPP__DELTA,
PERF_HPP__RATIO,
PERF_HPP__WEIGHTED_DIFF,
PERF_HPP__FORMULA,
PERF_HPP__MAX_INDEX
};
@ -177,8 +174,6 @@ enum {
void perf_hpp__init(void);
void perf_hpp__column_register(struct perf_hpp_fmt *format);
void perf_hpp__column_enable(unsigned col);
int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he,
bool color);
struct perf_evlist;
@ -245,11 +240,4 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused,
#endif
unsigned int hists__sort_list_width(struct hists *self);
double perf_diff__compute_delta(struct hist_entry *he, struct hist_entry *pair);
double perf_diff__compute_ratio(struct hist_entry *he, struct hist_entry *pair);
s64 perf_diff__compute_wdiff(struct hist_entry *he, struct hist_entry *pair);
int perf_diff__formula(struct hist_entry *he, struct hist_entry *pair,
char *buf, size_t size);
double perf_diff__period_percent(struct hist_entry *he, u64 period);
#endif /* __PERF_HIST_H */

View File

@ -1,3 +1,4 @@
#include <string.h>
void *memdup(const void *src, size_t len);
int str_append(char **s, int *len, const char *a);

View File

@ -233,7 +233,7 @@ void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size)
return;
}
static struct thread *__machine__findnew_thread(struct machine *machine, pid_t pid,
static struct thread *__machine__findnew_thread(struct machine *machine, pid_t tid,
bool create)
{
struct rb_node **p = &machine->threads.rb_node;
@ -241,23 +241,23 @@ static struct thread *__machine__findnew_thread(struct machine *machine, pid_t p
struct thread *th;
/*
* Font-end cache - PID lookups come in blocks,
* Front-end cache - TID lookups come in blocks,
* so most of the time we dont have to look up
* the full rbtree:
*/
if (machine->last_match && machine->last_match->pid == pid)
if (machine->last_match && machine->last_match->tid == tid)
return machine->last_match;
while (*p != NULL) {
parent = *p;
th = rb_entry(parent, struct thread, rb_node);
if (th->pid == pid) {
if (th->tid == tid) {
machine->last_match = th;
return th;
}
if (pid < th->pid)
if (tid < th->tid)
p = &(*p)->rb_left;
else
p = &(*p)->rb_right;
@ -266,7 +266,7 @@ static struct thread *__machine__findnew_thread(struct machine *machine, pid_t p
if (!create)
return NULL;
th = thread__new(pid);
th = thread__new(tid);
if (th != NULL) {
rb_link_node(&th->rb_node, parent, p);
rb_insert_color(&th->rb_node, &machine->threads);
@ -276,14 +276,14 @@ static struct thread *__machine__findnew_thread(struct machine *machine, pid_t p
return th;
}
struct thread *machine__findnew_thread(struct machine *machine, pid_t pid)
struct thread *machine__findnew_thread(struct machine *machine, pid_t tid)
{
return __machine__findnew_thread(machine, pid, true);
return __machine__findnew_thread(machine, tid, true);
}
struct thread *machine__find_thread(struct machine *machine, pid_t pid)
struct thread *machine__find_thread(struct machine *machine, pid_t tid)
{
return __machine__findnew_thread(machine, pid, false);
return __machine__findnew_thread(machine, tid, false);
}
int machine__process_comm_event(struct machine *machine, union perf_event *event)
@ -1058,11 +1058,10 @@ int machine__process_event(struct machine *machine, union perf_event *event)
return ret;
}
static bool symbol__match_parent_regex(struct symbol *sym)
static bool symbol__match_regex(struct symbol *sym, regex_t *regex)
{
if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
if (sym->name && !regexec(regex, sym->name, 0, NULL, 0))
return 1;
return 0;
}
@ -1159,8 +1158,8 @@ struct branch_info *machine__resolve_bstack(struct machine *machine,
static int machine__resolve_callchain_sample(struct machine *machine,
struct thread *thread,
struct ip_callchain *chain,
struct symbol **parent)
struct symbol **parent,
struct addr_location *root_al)
{
u8 cpumode = PERF_RECORD_MISC_USER;
unsigned int i;
@ -1211,8 +1210,15 @@ static int machine__resolve_callchain_sample(struct machine *machine,
MAP__FUNCTION, ip, &al, NULL);
if (al.sym != NULL) {
if (sort__has_parent && !*parent &&
symbol__match_parent_regex(al.sym))
symbol__match_regex(al.sym, &parent_regex))
*parent = al.sym;
else if (have_ignore_callees && root_al &&
symbol__match_regex(al.sym, &ignore_callees_regex)) {
/* Treat this symbol as the root,
forgetting its callees. */
*root_al = al;
callchain_cursor_reset(&callchain_cursor);
}
if (!symbol_conf.use_callchain)
break;
}
@ -1237,15 +1243,13 @@ int machine__resolve_callchain(struct machine *machine,
struct perf_evsel *evsel,
struct thread *thread,
struct perf_sample *sample,
struct symbol **parent)
struct symbol **parent,
struct addr_location *root_al)
{
int ret;
callchain_cursor_reset(&callchain_cursor);
ret = machine__resolve_callchain_sample(machine, thread,
sample->callchain, parent);
sample->callchain, parent, root_al);
if (ret)
return ret;

View File

@ -5,6 +5,7 @@
#include <linux/rbtree.h>
#include "map.h"
struct addr_location;
struct branch_stack;
struct perf_evsel;
struct perf_sample;
@ -36,7 +37,7 @@ struct map *machine__kernel_map(struct machine *machine, enum map_type type)
return machine->vmlinux_maps[type];
}
struct thread *machine__find_thread(struct machine *machine, pid_t pid);
struct thread *machine__find_thread(struct machine *machine, pid_t tid);
int machine__process_comm_event(struct machine *machine, union perf_event *event);
int machine__process_exit_event(struct machine *machine, union perf_event *event);
@ -83,7 +84,8 @@ int machine__resolve_callchain(struct machine *machine,
struct perf_evsel *evsel,
struct thread *thread,
struct perf_sample *sample,
struct symbol **parent);
struct symbol **parent,
struct addr_location *root_al);
/*
* Default guest kernel is defined by parameter --guestkallsyms
@ -99,7 +101,7 @@ static inline bool machine__is_host(struct machine *machine)
return machine ? machine->pid == HOST_KERNEL_ID : false;
}
struct thread *machine__findnew_thread(struct machine *machine, pid_t pid);
struct thread *machine__findnew_thread(struct machine *machine, pid_t tid);
size_t machine__fprintf(struct machine *machine, FILE *fp);

View File

@ -6,7 +6,7 @@
#include "parse-options.h"
#include "parse-events.h"
#include "exec_cmd.h"
#include "string.h"
#include "linux/string.h"
#include "symbol.h"
#include "cache.h"
#include "header.h"
@ -217,6 +217,29 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config)
return NULL;
}
struct tracepoint_path *tracepoint_name_to_path(const char *name)
{
struct tracepoint_path *path = zalloc(sizeof(*path));
char *str = strchr(name, ':');
if (path == NULL || str == NULL) {
free(path);
return NULL;
}
path->system = strndup(name, str - name);
path->name = strdup(str+1);
if (path->system == NULL || path->name == NULL) {
free(path->system);
free(path->name);
free(path);
path = NULL;
}
return path;
}
const char *event_type(int type)
{
switch (type) {
@ -241,40 +264,29 @@ const char *event_type(int type)
static int __add_event(struct list_head **_list, int *idx,
static int __add_event(struct list_head *list, int *idx,
struct perf_event_attr *attr,
char *name, struct cpu_map *cpus)
{
struct perf_evsel *evsel;
struct list_head *list = *_list;
if (!list) {
list = malloc(sizeof(*list));
if (!list)
return -ENOMEM;
INIT_LIST_HEAD(list);
}
event_attr_init(attr);
evsel = perf_evsel__new(attr, (*idx)++);
if (!evsel) {
free(list);
if (!evsel)
return -ENOMEM;
}
evsel->cpus = cpus;
if (name)
evsel->name = strdup(name);
list_add_tail(&evsel->node, list);
*_list = list;
return 0;
}
static int add_event(struct list_head **_list, int *idx,
static int add_event(struct list_head *list, int *idx,
struct perf_event_attr *attr, char *name)
{
return __add_event(_list, idx, attr, name, NULL);
return __add_event(list, idx, attr, name, NULL);
}
static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES], int size)
@ -295,7 +307,7 @@ static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES]
return -1;
}
int parse_events_add_cache(struct list_head **list, int *idx,
int parse_events_add_cache(struct list_head *list, int *idx,
char *type, char *op_result1, char *op_result2)
{
struct perf_event_attr attr;
@ -356,31 +368,21 @@ int parse_events_add_cache(struct list_head **list, int *idx,
return add_event(list, idx, &attr, name);
}
static int add_tracepoint(struct list_head **listp, int *idx,
static int add_tracepoint(struct list_head *list, int *idx,
char *sys_name, char *evt_name)
{
struct perf_evsel *evsel;
struct list_head *list = *listp;
if (!list) {
list = malloc(sizeof(*list));
if (!list)
return -ENOMEM;
INIT_LIST_HEAD(list);
}
evsel = perf_evsel__newtp(sys_name, evt_name, (*idx)++);
if (!evsel) {
free(list);
if (!evsel)
return -ENOMEM;
}
list_add_tail(&evsel->node, list);
*listp = list;
return 0;
}
static int add_tracepoint_multi_event(struct list_head **list, int *idx,
static int add_tracepoint_multi_event(struct list_head *list, int *idx,
char *sys_name, char *evt_name)
{
char evt_path[MAXPATHLEN];
@ -412,7 +414,7 @@ static int add_tracepoint_multi_event(struct list_head **list, int *idx,
return ret;
}
static int add_tracepoint_event(struct list_head **list, int *idx,
static int add_tracepoint_event(struct list_head *list, int *idx,
char *sys_name, char *evt_name)
{
return strpbrk(evt_name, "*?") ?
@ -420,7 +422,7 @@ static int add_tracepoint_event(struct list_head **list, int *idx,
add_tracepoint(list, idx, sys_name, evt_name);
}
static int add_tracepoint_multi_sys(struct list_head **list, int *idx,
static int add_tracepoint_multi_sys(struct list_head *list, int *idx,
char *sys_name, char *evt_name)
{
struct dirent *events_ent;
@ -452,7 +454,7 @@ static int add_tracepoint_multi_sys(struct list_head **list, int *idx,
return ret;
}
int parse_events_add_tracepoint(struct list_head **list, int *idx,
int parse_events_add_tracepoint(struct list_head *list, int *idx,
char *sys, char *event)
{
int ret;
@ -507,7 +509,7 @@ do { \
return 0;
}
int parse_events_add_breakpoint(struct list_head **list, int *idx,
int parse_events_add_breakpoint(struct list_head *list, int *idx,
void *ptr, char *type)
{
struct perf_event_attr attr;
@ -588,7 +590,7 @@ static int config_attr(struct perf_event_attr *attr,
return 0;
}
int parse_events_add_numeric(struct list_head **list, int *idx,
int parse_events_add_numeric(struct list_head *list, int *idx,
u32 type, u64 config,
struct list_head *head_config)
{
@ -621,7 +623,7 @@ static char *pmu_event_name(struct list_head *head_terms)
return NULL;
}
int parse_events_add_pmu(struct list_head **list, int *idx,
int parse_events_add_pmu(struct list_head *list, int *idx,
char *name, struct list_head *head_config)
{
struct perf_event_attr attr;
@ -664,6 +666,7 @@ void parse_events__set_leader(char *name, struct list_head *list)
leader->group_name = name ? strdup(name) : NULL;
}
/* list_event is assumed to point to malloc'ed memory */
void parse_events_update_lists(struct list_head *list_event,
struct list_head *list_all)
{
@ -820,6 +823,32 @@ int parse_events_name(struct list_head *list, char *name)
return 0;
}
static int parse_events__scanner(const char *str, void *data, int start_token);
static int parse_events_fixup(int ret, const char *str, void *data,
int start_token)
{
char *o = strdup(str);
char *s = NULL;
char *t = o;
char *p;
int len = 0;
if (!o)
return ret;
while ((p = strsep(&t, ",")) != NULL) {
if (s)
str_append(&s, &len, ",");
str_append(&s, &len, "cpu/");
str_append(&s, &len, p);
str_append(&s, &len, "/");
}
free(o);
if (!s)
return -ENOMEM;
return parse_events__scanner(s, data, start_token);
}
static int parse_events__scanner(const char *str, void *data, int start_token)
{
YY_BUFFER_STATE buffer;
@ -840,6 +869,8 @@ static int parse_events__scanner(const char *str, void *data, int start_token)
parse_events__flush_buffer(buffer, scanner);
parse_events__delete_buffer(buffer, scanner);
parse_events_lex_destroy(scanner);
if (ret && !strchr(str, '/'))
ret = parse_events_fixup(ret, str, data, start_token);
return ret;
}
@ -1079,6 +1110,8 @@ int print_hwcache_events(const char *event_glob, bool name_only)
}
}
if (printed)
printf("\n");
return printed;
}
@ -1133,11 +1166,12 @@ void print_events(const char *event_glob, bool name_only)
print_hwcache_events(event_glob, name_only);
print_pmu_events(event_glob, name_only);
if (event_glob != NULL)
return;
if (!name_only) {
printf("\n");
printf(" %-50s [%s]\n",
"rNNN",
event_type_descriptors[PERF_TYPE_RAW]);
@ -1237,6 +1271,4 @@ void parse_events__free_terms(struct list_head *terms)
list_for_each_entry_safe(term, h, terms, list)
free(term);
free(terms);
}

View File

@ -23,6 +23,7 @@ struct tracepoint_path {
};
extern struct tracepoint_path *tracepoint_id_to_path(u64 config);
extern struct tracepoint_path *tracepoint_name_to_path(const char *name);
extern bool have_tracepoints(struct list_head *evlist);
const char *event_type(int type);
@ -84,16 +85,16 @@ void parse_events__free_terms(struct list_head *terms);
int parse_events__modifier_event(struct list_head *list, char *str, bool add);
int parse_events__modifier_group(struct list_head *list, char *event_mod);
int parse_events_name(struct list_head *list, char *name);
int parse_events_add_tracepoint(struct list_head **list, int *idx,
int parse_events_add_tracepoint(struct list_head *list, int *idx,
char *sys, char *event);
int parse_events_add_numeric(struct list_head **list, int *idx,
int parse_events_add_numeric(struct list_head *list, int *idx,
u32 type, u64 config,
struct list_head *head_config);
int parse_events_add_cache(struct list_head **list, int *idx,
int parse_events_add_cache(struct list_head *list, int *idx,
char *type, char *op_result1, char *op_result2);
int parse_events_add_breakpoint(struct list_head **list, int *idx,
int parse_events_add_breakpoint(struct list_head *list, int *idx,
void *ptr, char *type);
int parse_events_add_pmu(struct list_head **list, int *idx,
int parse_events_add_pmu(struct list_head *list, int *idx,
char *pmu , struct list_head *head_config);
void parse_events__set_leader(char *name, struct list_head *list);
void parse_events_update_lists(struct list_head *list_event,

View File

@ -22,6 +22,13 @@ do { \
YYABORT; \
} while (0)
#define ALLOC_LIST(list) \
do { \
list = malloc(sizeof(*list)); \
ABORT_ON(!list); \
INIT_LIST_HEAD(list); \
} while (0)
static inc_group_count(struct list_head *list,
struct parse_events_evlist *data)
{
@ -196,9 +203,10 @@ event_pmu:
PE_NAME '/' event_config '/'
{
struct parse_events_evlist *data = _data;
struct list_head *list = NULL;
struct list_head *list;
ABORT_ON(parse_events_add_pmu(&list, &data->idx, $1, $3));
ALLOC_LIST(list);
ABORT_ON(parse_events_add_pmu(list, &data->idx, $1, $3));
parse_events__free_terms($3);
$$ = list;
}
@ -212,11 +220,12 @@ event_legacy_symbol:
value_sym '/' event_config '/'
{
struct parse_events_evlist *data = _data;
struct list_head *list = NULL;
struct list_head *list;
int type = $1 >> 16;
int config = $1 & 255;
ABORT_ON(parse_events_add_numeric(&list, &data->idx,
ALLOC_LIST(list);
ABORT_ON(parse_events_add_numeric(list, &data->idx,
type, config, $3));
parse_events__free_terms($3);
$$ = list;
@ -225,11 +234,12 @@ value_sym '/' event_config '/'
value_sym sep_slash_dc
{
struct parse_events_evlist *data = _data;
struct list_head *list = NULL;
struct list_head *list;
int type = $1 >> 16;
int config = $1 & 255;
ABORT_ON(parse_events_add_numeric(&list, &data->idx,
ALLOC_LIST(list);
ABORT_ON(parse_events_add_numeric(list, &data->idx,
type, config, NULL));
$$ = list;
}
@ -238,27 +248,30 @@ event_legacy_cache:
PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT
{
struct parse_events_evlist *data = _data;
struct list_head *list = NULL;
struct list_head *list;
ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, $5));
ALLOC_LIST(list);
ABORT_ON(parse_events_add_cache(list, &data->idx, $1, $3, $5));
$$ = list;
}
|
PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT
{
struct parse_events_evlist *data = _data;
struct list_head *list = NULL;
struct list_head *list;
ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, NULL));
ALLOC_LIST(list);
ABORT_ON(parse_events_add_cache(list, &data->idx, $1, $3, NULL));
$$ = list;
}
|
PE_NAME_CACHE_TYPE
{
struct parse_events_evlist *data = _data;
struct list_head *list = NULL;
struct list_head *list;
ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, NULL, NULL));
ALLOC_LIST(list);
ABORT_ON(parse_events_add_cache(list, &data->idx, $1, NULL, NULL));
$$ = list;
}
@ -266,9 +279,10 @@ event_legacy_mem:
PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
{
struct parse_events_evlist *data = _data;
struct list_head *list = NULL;
struct list_head *list;
ABORT_ON(parse_events_add_breakpoint(&list, &data->idx,
ALLOC_LIST(list);
ABORT_ON(parse_events_add_breakpoint(list, &data->idx,
(void *) $2, $4));
$$ = list;
}
@ -276,9 +290,10 @@ PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
PE_PREFIX_MEM PE_VALUE sep_dc
{
struct parse_events_evlist *data = _data;
struct list_head *list = NULL;
struct list_head *list;
ABORT_ON(parse_events_add_breakpoint(&list, &data->idx,
ALLOC_LIST(list);
ABORT_ON(parse_events_add_breakpoint(list, &data->idx,
(void *) $2, NULL));
$$ = list;
}
@ -287,9 +302,10 @@ event_legacy_tracepoint:
PE_NAME ':' PE_NAME
{
struct parse_events_evlist *data = _data;
struct list_head *list = NULL;
struct list_head *list;
ABORT_ON(parse_events_add_tracepoint(&list, &data->idx, $1, $3));
ALLOC_LIST(list);
ABORT_ON(parse_events_add_tracepoint(list, &data->idx, $1, $3));
$$ = list;
}
@ -297,9 +313,10 @@ event_legacy_numeric:
PE_VALUE ':' PE_VALUE
{
struct parse_events_evlist *data = _data;
struct list_head *list = NULL;
struct list_head *list;
ABORT_ON(parse_events_add_numeric(&list, &data->idx, (u32)$1, $3, NULL));
ALLOC_LIST(list);
ABORT_ON(parse_events_add_numeric(list, &data->idx, (u32)$1, $3, NULL));
$$ = list;
}
@ -307,9 +324,10 @@ event_legacy_raw:
PE_RAW
{
struct parse_events_evlist *data = _data;
struct list_head *list = NULL;
struct list_head *list;
ABORT_ON(parse_events_add_numeric(&list, &data->idx,
ALLOC_LIST(list);
ABORT_ON(parse_events_add_numeric(list, &data->idx,
PERF_TYPE_RAW, $1, NULL));
$$ = list;
}

View File

@ -73,7 +73,7 @@ int perf_pmu__format_parse(char *dir, struct list_head *head)
* located at:
* /sys/bus/event_source/devices/<dev>/format as sysfs group attributes.
*/
static int pmu_format(char *name, struct list_head *format)
static int pmu_format(const char *name, struct list_head *format)
{
struct stat st;
char path[PATH_MAX];
@ -162,7 +162,7 @@ static int pmu_aliases_parse(char *dir, struct list_head *head)
* Reading the pmu event aliases definition, which should be located at:
* /sys/bus/event_source/devices/<dev>/events as sysfs group attributes.
*/
static int pmu_aliases(char *name, struct list_head *head)
static int pmu_aliases(const char *name, struct list_head *head)
{
struct stat st;
char path[PATH_MAX];
@ -208,7 +208,7 @@ static int pmu_alias_terms(struct perf_pmu_alias *alias,
* located at:
* /sys/bus/event_source/devices/<dev>/type as sysfs attribute.
*/
static int pmu_type(char *name, __u32 *type)
static int pmu_type(const char *name, __u32 *type)
{
struct stat st;
char path[PATH_MAX];
@ -266,7 +266,7 @@ static void pmu_read_sysfs(void)
closedir(dir);
}
static struct cpu_map *pmu_cpumask(char *name)
static struct cpu_map *pmu_cpumask(const char *name)
{
struct stat st;
char path[PATH_MAX];
@ -293,7 +293,7 @@ static struct cpu_map *pmu_cpumask(char *name)
return cpus;
}
static struct perf_pmu *pmu_lookup(char *name)
static struct perf_pmu *pmu_lookup(const char *name)
{
struct perf_pmu *pmu;
LIST_HEAD(format);
@ -330,7 +330,7 @@ static struct perf_pmu *pmu_lookup(char *name)
return pmu;
}
static struct perf_pmu *pmu_find(char *name)
static struct perf_pmu *pmu_find(const char *name)
{
struct perf_pmu *pmu;
@ -356,7 +356,7 @@ struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu)
return NULL;
}
struct perf_pmu *perf_pmu__find(char *name)
struct perf_pmu *perf_pmu__find(const char *name)
{
struct perf_pmu *pmu;
@ -564,3 +564,76 @@ void perf_pmu__set_format(unsigned long *bits, long from, long to)
for (b = from; b <= to; b++)
set_bit(b, bits);
}
static char *format_alias(char *buf, int len, struct perf_pmu *pmu,
struct perf_pmu_alias *alias)
{
snprintf(buf, len, "%s/%s/", pmu->name, alias->name);
return buf;
}
static char *format_alias_or(char *buf, int len, struct perf_pmu *pmu,
struct perf_pmu_alias *alias)
{
snprintf(buf, len, "%s OR %s/%s/", alias->name, pmu->name, alias->name);
return buf;
}
static int cmp_string(const void *a, const void *b)
{
const char * const *as = a;
const char * const *bs = b;
return strcmp(*as, *bs);
}
void print_pmu_events(const char *event_glob, bool name_only)
{
struct perf_pmu *pmu;
struct perf_pmu_alias *alias;
char buf[1024];
int printed = 0;
int len, j;
char **aliases;
pmu = NULL;
len = 0;
while ((pmu = perf_pmu__scan(pmu)) != NULL)
list_for_each_entry(alias, &pmu->aliases, list)
len++;
aliases = malloc(sizeof(char *) * len);
if (!aliases)
return;
pmu = NULL;
j = 0;
while ((pmu = perf_pmu__scan(pmu)) != NULL)
list_for_each_entry(alias, &pmu->aliases, list) {
char *name = format_alias(buf, sizeof(buf), pmu, alias);
bool is_cpu = !strcmp(pmu->name, "cpu");
if (event_glob != NULL &&
!(strglobmatch(name, event_glob) ||
(!is_cpu && strglobmatch(alias->name,
event_glob))))
continue;
aliases[j] = name;
if (is_cpu && !name_only)
aliases[j] = format_alias_or(buf, sizeof(buf),
pmu, alias);
aliases[j] = strdup(aliases[j]);
j++;
}
len = j;
qsort(aliases, len, sizeof(char *), cmp_string);
for (j = 0; j < len; j++) {
if (name_only) {
printf("%s ", aliases[j]);
continue;
}
printf(" %-50s [Kernel PMU event]\n", aliases[j]);
free(aliases[j]);
printed++;
}
if (printed)
printf("\n");
free(aliases);
}

View File

@ -3,6 +3,7 @@
#include <linux/bitops.h>
#include <linux/perf_event.h>
#include <stdbool.h>
enum {
PERF_PMU_FORMAT_VALUE_CONFIG,
@ -21,7 +22,7 @@ struct perf_pmu {
struct list_head list;
};
struct perf_pmu *perf_pmu__find(char *name);
struct perf_pmu *perf_pmu__find(const char *name);
int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
struct list_head *head_terms);
int perf_pmu__config_terms(struct list_head *formats,
@ -40,5 +41,7 @@ int perf_pmu__format_parse(char *dir, struct list_head *head);
struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu);
void print_pmu_events(const char *event_glob, bool name_only);
int perf_pmu__test(void);
#endif /* __PMU_H */

View File

@ -1,4 +1,5 @@
#include <linux/kernel.h>
#include <traceevent/event-parse.h>
#include <byteswap.h>
#include <unistd.h>
@ -12,7 +13,6 @@
#include "sort.h"
#include "util.h"
#include "cpumap.h"
#include "event-parse.h"
#include "perf_regs.h"
#include "vdso.h"
@ -24,7 +24,7 @@ static int perf_session__open(struct perf_session *self, bool force)
self->fd_pipe = true;
self->fd = STDIN_FILENO;
if (perf_session__read_header(self, self->fd) < 0)
if (perf_session__read_header(self) < 0)
pr_err("incompatible file format (rerun with -v to learn more)");
return 0;
@ -56,7 +56,7 @@ static int perf_session__open(struct perf_session *self, bool force)
goto out_close;
}
if (perf_session__read_header(self, self->fd) < 0) {
if (perf_session__read_header(self) < 0) {
pr_err("incompatible file format (rerun with -v to learn more)");
goto out_close;
}
@ -193,7 +193,9 @@ void perf_session__delete(struct perf_session *self)
vdso__exit();
}
static int process_event_synth_tracing_data_stub(union perf_event *event
static int process_event_synth_tracing_data_stub(struct perf_tool *tool
__maybe_unused,
union perf_event *event
__maybe_unused,
struct perf_session *session
__maybe_unused)
@ -202,7 +204,8 @@ static int process_event_synth_tracing_data_stub(union perf_event *event
return 0;
}
static int process_event_synth_attr_stub(union perf_event *event __maybe_unused,
static int process_event_synth_attr_stub(struct perf_tool *tool __maybe_unused,
union perf_event *event __maybe_unused,
struct perf_evlist **pevlist
__maybe_unused)
{
@ -238,13 +241,6 @@ static int process_finished_round_stub(struct perf_tool *tool __maybe_unused,
return 0;
}
static int process_event_type_stub(struct perf_tool *tool __maybe_unused,
union perf_event *event __maybe_unused)
{
dump_printf(": unhandled!\n");
return 0;
}
static int process_finished_round(struct perf_tool *tool,
union perf_event *event,
struct perf_session *session);
@ -271,8 +267,6 @@ static void perf_tool__fill_defaults(struct perf_tool *tool)
tool->unthrottle = process_event_stub;
if (tool->attr == NULL)
tool->attr = process_event_synth_attr_stub;
if (tool->event_type == NULL)
tool->event_type = process_event_type_stub;
if (tool->tracing_data == NULL)
tool->tracing_data = process_event_synth_tracing_data_stub;
if (tool->build_id == NULL)
@ -921,16 +915,14 @@ static int perf_session__process_user_event(struct perf_session *session, union
/* These events are processed right away */
switch (event->header.type) {
case PERF_RECORD_HEADER_ATTR:
err = tool->attr(event, &session->evlist);
err = tool->attr(tool, event, &session->evlist);
if (err == 0)
perf_session__set_id_hdr_size(session);
return err;
case PERF_RECORD_HEADER_EVENT_TYPE:
return tool->event_type(tool, event);
case PERF_RECORD_HEADER_TRACING_DATA:
/* setup for reading amidst mmap */
lseek(session->fd, file_offset, SEEK_SET);
return tool->tracing_data(event, session);
return tool->tracing_data(tool, event, session);
case PERF_RECORD_HEADER_BUILD_ID:
return tool->build_id(tool, event, session);
case PERF_RECORD_FINISHED_ROUND:
@ -1091,8 +1083,10 @@ more:
perf_event_header__bswap(&event->header);
size = event->header.size;
if (size == 0)
size = 8;
if (size < sizeof(struct perf_event_header)) {
pr_err("bad event header size\n");
goto out_err;
}
if (size > cur_size) {
void *new = realloc(buf, size);
@ -1161,8 +1155,12 @@ fetch_mmaped_event(struct perf_session *session,
if (session->header.needs_swap)
perf_event_header__bswap(&event->header);
if (head + event->header.size > mmap_size)
if (head + event->header.size > mmap_size) {
/* We're not fetching the event so swap back again */
if (session->header.needs_swap)
perf_event_header__bswap(&event->header);
return NULL;
}
return event;
}
@ -1242,7 +1240,7 @@ more:
size = event->header.size;
if (size == 0 ||
if (size < sizeof(struct perf_event_header) ||
perf_session__process_event(session, event, tool, file_pos) < 0) {
pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n",
file_offset + head, event->header.size,
@ -1397,9 +1395,8 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
if (symbol_conf.use_callchain && sample->callchain) {
if (machine__resolve_callchain(machine, evsel, al.thread,
sample, NULL) != 0) {
sample, NULL, NULL) != 0) {
if (verbose)
error("Failed to resolve callchain. Skipping\n");
return;

View File

@ -37,7 +37,6 @@ struct perf_session {
int fd;
bool fd_pipe;
bool repipe;
char *cwd;
struct ordered_samples ordered_samples;
char filename[1];
};

View File

@ -7,6 +7,8 @@ const char default_parent_pattern[] = "^sys_|^do_page_fault";
const char *parent_pattern = default_parent_pattern;
const char default_sort_order[] = "comm,dso,symbol";
const char *sort_order = default_sort_order;
regex_t ignore_callees_regex;
int have_ignore_callees = 0;
int sort__need_collapse = 0;
int sort__has_parent = 0;
int sort__has_sym = 0;
@ -55,14 +57,14 @@ static int64_t cmp_null(void *l, void *r)
static int64_t
sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
{
return right->thread->pid - left->thread->pid;
return right->thread->tid - left->thread->tid;
}
static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf,
size_t size, unsigned int width)
{
return repsep_snprintf(bf, size, "%*s:%5d", width - 6,
self->thread->comm ?: "", self->thread->pid);
self->thread->comm ?: "", self->thread->tid);
}
struct sort_entry sort_thread = {
@ -77,7 +79,7 @@ struct sort_entry sort_thread = {
static int64_t
sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
{
return right->thread->pid - left->thread->pid;
return right->thread->tid - left->thread->tid;
}
static int64_t

View File

@ -29,6 +29,8 @@ extern const char *sort_order;
extern const char default_parent_pattern[];
extern const char *parent_pattern;
extern const char default_sort_order[];
extern regex_t ignore_callees_regex;
extern int have_ignore_callees;
extern int sort__need_collapse;
extern int sort__has_parent;
extern int sort__has_sym;
@ -87,6 +89,9 @@ struct hist_entry {
struct hist_entry_diff diff;
/* We are added by hists__add_dummy_entry. */
bool dummy;
/* XXX These two should move to some tree widget lib */
u16 row_offset;
u16 nr_rows;
@ -183,4 +188,6 @@ int setup_sorting(void);
extern int sort_dimension__add(const char *);
void sort__setup_elide(FILE *fp);
int report_parse_ignore_callees_opt(const struct option *opt, const char *arg, int unset);
#endif /* __PERF_SORT_H */

View File

@ -387,3 +387,27 @@ void *memdup(const void *src, size_t len)
return p;
}
/**
* str_append - reallocate string and append another
* @s: pointer to string pointer
* @len: pointer to len (initialized)
* @a: string to append.
*/
int str_append(char **s, int *len, const char *a)
{
int olen = *s ? strlen(*s) : 0;
int nlen = olen + strlen(a) + 1;
if (*len < nlen) {
*len = *len * 2;
if (*len < nlen)
*len = nlen;
*s = realloc(*s, *len);
if (!*s)
return -ENOMEM;
if (olen == 0)
**s = 0;
}
strcat(*s, a);
return 0;
}

View File

@ -888,8 +888,11 @@ int dso__load_vmlinux(struct dso *dso, struct map *map,
char symfs_vmlinux[PATH_MAX];
enum dso_binary_type symtab_type;
snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s",
symbol_conf.symfs, vmlinux);
if (vmlinux[0] == '/')
snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s", vmlinux);
else
snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s",
symbol_conf.symfs, vmlinux);
if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX;

View File

@ -7,17 +7,17 @@
#include "util.h"
#include "debug.h"
struct thread *thread__new(pid_t pid)
struct thread *thread__new(pid_t tid)
{
struct thread *self = zalloc(sizeof(*self));
if (self != NULL) {
map_groups__init(&self->mg);
self->pid = pid;
self->tid = tid;
self->ppid = -1;
self->comm = malloc(32);
if (self->comm)
snprintf(self->comm, 32, ":%d", self->pid);
snprintf(self->comm, 32, ":%d", self->tid);
}
return self;
@ -57,7 +57,7 @@ int thread__comm_len(struct thread *self)
size_t thread__fprintf(struct thread *thread, FILE *fp)
{
return fprintf(fp, "Thread %d %s\n", thread->pid, thread->comm) +
return fprintf(fp, "Thread %d %s\n", thread->tid, thread->comm) +
map_groups__fprintf(&thread->mg, verbose, fp);
}
@ -84,7 +84,7 @@ int thread__fork(struct thread *self, struct thread *parent)
if (map_groups__clone(&self->mg, &parent->mg, i) < 0)
return -ENOMEM;
self->ppid = parent->pid;
self->ppid = parent->tid;
return 0;
}

View File

@ -12,7 +12,7 @@ struct thread {
struct list_head node;
};
struct map_groups mg;
pid_t pid;
pid_t tid;
pid_t ppid;
char shortname[3];
bool comm_set;
@ -24,7 +24,7 @@ struct thread {
struct machine;
struct thread *thread__new(pid_t pid);
struct thread *thread__new(pid_t tid);
void thread__delete(struct thread *self);
int thread__set_comm(struct thread *self, const char *comm);
@ -47,4 +47,14 @@ void thread__find_addr_location(struct thread *thread, struct machine *machine,
u8 cpumode, enum map_type type, u64 addr,
struct addr_location *al,
symbol_filter_t filter);
static inline void *thread__priv(struct thread *thread)
{
return thread->priv;
}
static inline void thread__set_priv(struct thread *thread, void *p)
{
thread->priv = p;
}
#endif /* __PERF_THREAD_H */

View File

@ -18,12 +18,9 @@ typedef int (*event_sample)(struct perf_tool *tool, union perf_event *event,
typedef int (*event_op)(struct perf_tool *tool, union perf_event *event,
struct perf_sample *sample, struct machine *machine);
typedef int (*event_attr_op)(union perf_event *event,
typedef int (*event_attr_op)(struct perf_tool *tool,
union perf_event *event,
struct perf_evlist **pevlist);
typedef int (*event_simple_op)(struct perf_tool *tool, union perf_event *event);
typedef int (*event_synth_op)(union perf_event *event,
struct perf_session *session);
typedef int (*event_op2)(struct perf_tool *tool, union perf_event *event,
struct perf_session *session);
@ -39,8 +36,7 @@ struct perf_tool {
throttle,
unthrottle;
event_attr_op attr;
event_synth_op tracing_data;
event_simple_op event_type;
event_op2 tracing_data;
event_op2 finished_round,
build_id;
bool ordered_samples;

View File

@ -46,65 +46,6 @@
static int output_fd;
static const char *find_debugfs(void)
{
const char *path = perf_debugfs_mount(NULL);
if (!path)
pr_debug("Your kernel does not support the debugfs filesystem");
return path;
}
/*
* Finds the path to the debugfs/tracing
* Allocates the string and stores it.
*/
static const char *find_tracing_dir(void)
{
static char *tracing;
static int tracing_found;
const char *debugfs;
if (tracing_found)
return tracing;
debugfs = find_debugfs();
if (!debugfs)
return NULL;
tracing = malloc(strlen(debugfs) + 9);
if (!tracing)
return NULL;
sprintf(tracing, "%s/tracing", debugfs);
tracing_found = 1;
return tracing;
}
static char *get_tracing_file(const char *name)
{
const char *tracing;
char *file;
tracing = find_tracing_dir();
if (!tracing)
return NULL;
file = malloc(strlen(tracing) + strlen(name) + 2);
if (!file)
return NULL;
sprintf(file, "%s/%s", tracing, name);
return file;
}
static void put_tracing_file(char *file)
{
free(file);
}
int bigendian(void)
{
unsigned char str[] = { 0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0, 0x0};
@ -160,7 +101,7 @@ out:
return err;
}
static int read_header_files(void)
static int record_header_files(void)
{
char *path;
struct stat st;
@ -299,7 +240,7 @@ out:
return err;
}
static int read_ftrace_files(struct tracepoint_path *tps)
static int record_ftrace_files(struct tracepoint_path *tps)
{
char *path;
int ret;
@ -328,7 +269,7 @@ static bool system_in_tp_list(char *sys, struct tracepoint_path *tps)
return false;
}
static int read_event_files(struct tracepoint_path *tps)
static int record_event_files(struct tracepoint_path *tps)
{
struct dirent *dent;
struct stat st;
@ -403,7 +344,7 @@ out:
return err;
}
static int read_proc_kallsyms(void)
static int record_proc_kallsyms(void)
{
unsigned int size;
const char *path = "/proc/kallsyms";
@ -421,7 +362,7 @@ static int read_proc_kallsyms(void)
return record_file(path, 4);
}
static int read_ftrace_printk(void)
static int record_ftrace_printk(void)
{
unsigned int size;
char *path;
@ -473,12 +414,27 @@ get_tracepoints_path(struct list_head *pattrs)
if (pos->attr.type != PERF_TYPE_TRACEPOINT)
continue;
++nr_tracepoints;
if (pos->name) {
ppath->next = tracepoint_name_to_path(pos->name);
if (ppath->next)
goto next;
if (strchr(pos->name, ':') == NULL)
goto try_id;
goto error;
}
try_id:
ppath->next = tracepoint_id_to_path(pos->attr.config);
if (!ppath->next) {
error:
pr_debug("No memory to alloc tracepoints list\n");
put_tracepoints_path(&path);
return NULL;
}
next:
ppath = ppath->next;
}
@ -520,8 +476,6 @@ static int tracing_data_header(void)
else
buf[0] = 0;
read_trace_init(buf[0], buf[0]);
if (write(output_fd, buf, 1) != 1)
return -1;
@ -583,19 +537,19 @@ struct tracing_data *tracing_data_get(struct list_head *pattrs,
err = tracing_data_header();
if (err)
goto out;
err = read_header_files();
err = record_header_files();
if (err)
goto out;
err = read_ftrace_files(tps);
err = record_ftrace_files(tps);
if (err)
goto out;
err = read_event_files(tps);
err = record_event_files(tps);
if (err)
goto out;
err = read_proc_kallsyms();
err = record_proc_kallsyms();
if (err)
goto out;
err = read_ftrace_printk();
err = record_ftrace_printk();
out:
/*

View File

@ -28,12 +28,6 @@
#include "util.h"
#include "trace-event.h"
int header_page_size_size;
int header_page_ts_size;
int header_page_data_offset;
bool latency_format;
struct pevent *read_trace_init(int file_bigendian, int host_bigendian)
{
struct pevent *pevent = pevent_alloc();

View File

@ -39,10 +39,6 @@
static int input_fd;
int file_bigendian;
int host_bigendian;
static int long_size;
static ssize_t trace_data_size;
static bool repipe;
@ -216,7 +212,7 @@ static int read_ftrace_printk(struct pevent *pevent)
static int read_header_files(struct pevent *pevent)
{
unsigned long long size;
char *header_event;
char *header_page;
char buf[BUFSIZ];
int ret = 0;
@ -229,13 +225,26 @@ static int read_header_files(struct pevent *pevent)
}
size = read8(pevent);
skip(size);
/*
* The size field in the page is of type long,
* use that instead, since it represents the kernel.
*/
long_size = header_page_size_size;
header_page = malloc(size);
if (header_page == NULL)
return -1;
if (do_read(header_page, size) < 0) {
pr_debug("did not read header page");
free(header_page);
return -1;
}
if (!pevent_parse_header_page(pevent, header_page, size,
pevent_get_long_size(pevent))) {
/*
* The commit field in the page is of type long,
* use that instead, since it represents the kernel.
*/
pevent_set_long_size(pevent, pevent->header_page_size_size);
}
free(header_page);
if (do_read(buf, 13) < 0)
return -1;
@ -246,14 +255,8 @@ static int read_header_files(struct pevent *pevent)
}
size = read8(pevent);
header_event = malloc(size);
if (header_event == NULL)
return -1;
skip(size);
if (do_read(header_event, size) < 0)
ret = -1;
free(header_event);
return ret;
}
@ -349,6 +352,10 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe)
int show_funcs = 0;
int show_printk = 0;
ssize_t size = -1;
int file_bigendian;
int host_bigendian;
int file_long_size;
int file_page_size;
struct pevent *pevent;
int err;
@ -391,12 +398,15 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe)
if (do_read(buf, 1) < 0)
goto out;
long_size = buf[0];
file_long_size = buf[0];
page_size = read4(pevent);
if (!page_size)
file_page_size = read4(pevent);
if (!file_page_size)
goto out;
pevent_set_long_size(pevent, file_long_size);
pevent_set_page_size(pevent, file_page_size);
err = read_header_files(pevent);
if (err)
goto out;

View File

@ -1,8 +1,8 @@
#ifndef _PERF_UTIL_TRACE_EVENT_H
#define _PERF_UTIL_TRACE_EVENT_H
#include <traceevent/event-parse.h>
#include "parse-events.h"
#include "event-parse.h"
#include "session.h"
struct machine;
@ -10,23 +10,8 @@ struct perf_sample;
union perf_event;
struct perf_tool;
extern int header_page_size_size;
extern int header_page_ts_size;
extern int header_page_data_offset;
extern bool latency_format;
extern struct pevent *perf_pevent;
enum {
RINGBUF_TYPE_PADDING = 29,
RINGBUF_TYPE_TIME_EXTEND = 30,
RINGBUF_TYPE_TIME_STAMP = 31,
};
#ifndef TS_SHIFT
#define TS_SHIFT 27
#endif
int bigendian(void);
struct pevent *read_trace_init(int file_bigendian, int host_bigendian);

View File

@ -269,3 +269,62 @@ void perf_debugfs_set_path(const char *mntpt)
snprintf(debugfs_mountpoint, strlen(debugfs_mountpoint), "%s", mntpt);
set_tracing_events_path(mntpt);
}
static const char *find_debugfs(void)
{
const char *path = perf_debugfs_mount(NULL);
if (!path)
fprintf(stderr, "Your kernel does not support the debugfs filesystem");
return path;
}
/*
* Finds the path to the debugfs/tracing
* Allocates the string and stores it.
*/
const char *find_tracing_dir(void)
{
static char *tracing;
static int tracing_found;
const char *debugfs;
if (tracing_found)
return tracing;
debugfs = find_debugfs();
if (!debugfs)
return NULL;
tracing = malloc(strlen(debugfs) + 9);
if (!tracing)
return NULL;
sprintf(tracing, "%s/tracing", debugfs);
tracing_found = 1;
return tracing;
}
char *get_tracing_file(const char *name)
{
const char *tracing;
char *file;
tracing = find_tracing_dir();
if (!tracing)
return NULL;
file = malloc(strlen(tracing) + strlen(name) + 2);
if (!file)
return NULL;
sprintf(file, "%s/%s", tracing, name);
return file;
}
void put_tracing_file(char *file)
{
free(file);
}

View File

@ -80,6 +80,9 @@ extern char buildid_dir[];
extern char tracing_events_path[];
extern void perf_debugfs_set_path(const char *mountpoint);
const char *perf_debugfs_mount(const char *mountpoint);
const char *find_tracing_dir(void);
char *get_tracing_file(const char *name);
void put_tracing_file(char *file);
/* On most systems <limits.h> would have given us this, but
* not on some systems (e.g. GNU/Hurd).