| /* Copyright (C) 2021 Free Software Foundation, Inc. | |
| Contributed by Oracle. | |
| This file is part of GNU Binutils. | |
| 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 3, or (at your option) | |
| any later version. | |
| 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 General Public License for more details. | |
| You should have received a copy of the GNU General Public License | |
| along with this program; if not, write to the Free Software | |
| Foundation, 51 Franklin Street - Fifth Floor, Boston, | |
| MA 02110-1301, USA. */ | |
| #include "config.h" | |
| #include "CallStack.h" | |
| #include "DbeSession.h" | |
| #include "Exp_Layout.h" | |
| #include "Experiment.h" | |
| #include "Function.h" | |
| #include "Table.h" | |
| #include "dbe_types.h" | |
| #include "util.h" | |
| /* | |
| * PrUsage is a class which wraps access to the values of prusage | |
| * system structure. It was expanded to 64 bit entities in 2.7 | |
| * (experiment version 6 & 7). | |
| */ | |
| PrUsage::PrUsage () | |
| { | |
| pr_tstamp = pr_create = pr_term = pr_rtime = (hrtime_t) 0; | |
| pr_utime = pr_stime = pr_ttime = pr_tftime = pr_dftime = (hrtime_t) 0; | |
| pr_kftime = pr_ltime = pr_slptime = pr_wtime = pr_stoptime = (hrtime_t) 0; | |
| pr_minf = pr_majf = pr_nswap = pr_inblk = pr_oublk = 0; | |
| pr_msnd = pr_mrcv = pr_sigs = pr_vctx = pr_ictx = pr_sysc = pr_ioch = 0; | |
| } | |
| /* | |
| * Resource usage. /proc/<pid>/usage /proc/<pid>/lwp/<lwpid>/lwpusage | |
| */ | |
| struct timestruc_32 | |
| { /* v8 timestruc_t */ | |
| uint32_t tv_sec; /* seconds */ | |
| uint32_t tv_nsec; /* and nanoseconds */ | |
| }; | |
| typedef struct ana_prusage | |
| { | |
| id_t pr_lwpid; /* lwp id. 0: process or defunct */ | |
| int pr_count; /* number of contributing lwps */ | |
| timestruc_32 pr_tstamp; /* current time stamp */ | |
| timestruc_32 pr_create; /* process/lwp creation time stamp */ | |
| timestruc_32 pr_term; /* process/lwp termination time stamp */ | |
| timestruc_32 pr_rtime; /* total lwp real (elapsed) time */ | |
| timestruc_32 pr_utime; /* user level cpu time */ | |
| timestruc_32 pr_stime; /* system call cpu time */ | |
| timestruc_32 pr_ttime; /* other system trap cpu time */ | |
| timestruc_32 pr_tftime; /* text page fault sleep time */ | |
| timestruc_32 pr_dftime; /* data page fault sleep time */ | |
| timestruc_32 pr_kftime; /* kernel page fault sleep time */ | |
| timestruc_32 pr_ltime; /* user lock wait sleep time */ | |
| timestruc_32 pr_slptime; /* all other sleep time */ | |
| timestruc_32 pr_wtime; /* wait-cpu (latency) time */ | |
| timestruc_32 pr_stoptime; /* stopped time */ | |
| timestruc_32 filltime[6]; /* filler for future expansion */ | |
| uint32_t pr_minf; /* minor page faults */ | |
| uint32_t pr_majf; /* major page faults */ | |
| uint32_t pr_nswap; /* swaps */ | |
| uint32_t pr_inblk; /* input blocks */ | |
| uint32_t pr_oublk; /* output blocks */ | |
| uint32_t pr_msnd; /* messages sent */ | |
| uint32_t pr_mrcv; /* messages received */ | |
| uint32_t pr_sigs; /* signals received */ | |
| uint32_t pr_vctx; /* voluntary context switches */ | |
| uint32_t pr_ictx; /* involuntary context switches */ | |
| uint32_t pr_sysc; /* system calls */ | |
| uint32_t pr_ioch; /* chars read and written */ | |
| uint32_t filler[10]; /* filler for future expansion */ | |
| } raw_prusage_32; | |
| uint64_t | |
| PrUsage::bind32Size () | |
| { | |
| uint64_t bindSize = sizeof (raw_prusage_32); | |
| return bindSize; | |
| } | |
| #define timestruc2hr(x) ((hrtime_t)(x).tv_sec*NANOSEC + (hrtime_t)(x).tv_nsec) | |
| PrUsage * | |
| PrUsage::bind32 (void *p, bool need_swap_endian) | |
| { | |
| if (p == NULL) | |
| return NULL; | |
| raw_prusage_32 pu, *tmp = (raw_prusage_32*) p; | |
| if (need_swap_endian) | |
| { | |
| pu = *tmp; | |
| tmp = &pu; | |
| SWAP_ENDIAN (pu.pr_tstamp.tv_sec); | |
| SWAP_ENDIAN (pu.pr_tstamp.tv_nsec); | |
| SWAP_ENDIAN (pu.pr_create.tv_sec); | |
| SWAP_ENDIAN (pu.pr_create.tv_nsec); | |
| SWAP_ENDIAN (pu.pr_term.tv_sec); | |
| SWAP_ENDIAN (pu.pr_term.tv_nsec); | |
| SWAP_ENDIAN (pu.pr_rtime.tv_sec); | |
| SWAP_ENDIAN (pu.pr_rtime.tv_nsec); | |
| SWAP_ENDIAN (pu.pr_utime.tv_sec); | |
| SWAP_ENDIAN (pu.pr_utime.tv_nsec); | |
| SWAP_ENDIAN (pu.pr_stime.tv_sec); | |
| SWAP_ENDIAN (pu.pr_stime.tv_nsec); | |
| SWAP_ENDIAN (pu.pr_ttime.tv_sec); | |
| SWAP_ENDIAN (pu.pr_ttime.tv_nsec); | |
| SWAP_ENDIAN (pu.pr_tftime.tv_sec); | |
| SWAP_ENDIAN (pu.pr_tftime.tv_nsec); | |
| SWAP_ENDIAN (pu.pr_dftime.tv_sec); | |
| SWAP_ENDIAN (pu.pr_dftime.tv_nsec); | |
| SWAP_ENDIAN (pu.pr_kftime.tv_sec); | |
| SWAP_ENDIAN (pu.pr_kftime.tv_nsec); | |
| SWAP_ENDIAN (pu.pr_ltime.tv_sec); | |
| SWAP_ENDIAN (pu.pr_ltime.tv_nsec); | |
| SWAP_ENDIAN (pu.pr_slptime.tv_sec); | |
| SWAP_ENDIAN (pu.pr_slptime.tv_nsec); | |
| SWAP_ENDIAN (pu.pr_wtime.tv_sec); | |
| SWAP_ENDIAN (pu.pr_wtime.tv_nsec); | |
| SWAP_ENDIAN (pu.pr_stoptime.tv_sec); | |
| SWAP_ENDIAN (pu.pr_stoptime.tv_nsec); | |
| SWAP_ENDIAN (pu.pr_minf); | |
| SWAP_ENDIAN (pu.pr_majf); | |
| SWAP_ENDIAN (pu.pr_nswap); | |
| SWAP_ENDIAN (pu.pr_inblk); | |
| SWAP_ENDIAN (pu.pr_oublk); | |
| SWAP_ENDIAN (pu.pr_msnd); | |
| SWAP_ENDIAN (pu.pr_mrcv); | |
| SWAP_ENDIAN (pu.pr_sigs); | |
| SWAP_ENDIAN (pu.pr_vctx); | |
| SWAP_ENDIAN (pu.pr_ictx); | |
| SWAP_ENDIAN (pu.pr_sysc); | |
| SWAP_ENDIAN (pu.pr_ioch); | |
| } | |
| pr_tstamp = timestruc2hr (tmp->pr_tstamp); | |
| pr_create = timestruc2hr (tmp->pr_create); | |
| pr_term = timestruc2hr (tmp->pr_term); | |
| pr_rtime = timestruc2hr (tmp->pr_rtime); | |
| pr_utime = timestruc2hr (tmp->pr_utime); | |
| pr_stime = timestruc2hr (tmp->pr_stime); | |
| pr_ttime = timestruc2hr (tmp->pr_ttime); | |
| pr_tftime = timestruc2hr (tmp->pr_tftime); | |
| pr_dftime = timestruc2hr (tmp->pr_dftime); | |
| pr_kftime = timestruc2hr (tmp->pr_kftime); | |
| pr_ltime = timestruc2hr (tmp->pr_ltime); | |
| pr_slptime = timestruc2hr (tmp->pr_slptime); | |
| pr_wtime = timestruc2hr (tmp->pr_wtime); | |
| pr_stoptime = timestruc2hr (tmp->pr_stoptime); | |
| pr_minf = tmp->pr_minf; | |
| pr_majf = tmp->pr_majf; | |
| pr_nswap = tmp->pr_nswap; | |
| pr_inblk = tmp->pr_inblk; | |
| pr_oublk = tmp->pr_oublk; | |
| pr_msnd = tmp->pr_msnd; | |
| pr_mrcv = tmp->pr_mrcv; | |
| pr_sigs = tmp->pr_sigs; | |
| pr_vctx = tmp->pr_vctx; | |
| pr_ictx = tmp->pr_ictx; | |
| pr_sysc = tmp->pr_sysc; | |
| pr_ioch = tmp->pr_ioch; | |
| return this; | |
| } | |
| struct timestruc_64 | |
| { /* 64-bit timestruc_t */ | |
| uint64_t tv_sec; /* seconds */ | |
| uint64_t tv_nsec; /* and nanoseconds */ | |
| }; | |
| typedef struct | |
| { | |
| id_t pr_lwpid; /* lwp id. 0: process or defunct */ | |
| int pr_count; /* number of contributing lwps */ | |
| timestruc_64 pr_tstamp; /* current time stamp */ | |
| timestruc_64 pr_create; /* process/lwp creation time stamp */ | |
| timestruc_64 pr_term; /* process/lwp termination time stamp */ | |
| timestruc_64 pr_rtime; /* total lwp real (elapsed) time */ | |
| timestruc_64 pr_utime; /* user level cpu time */ | |
| timestruc_64 pr_stime; /* system call cpu time */ | |
| timestruc_64 pr_ttime; /* other system trap cpu time */ | |
| timestruc_64 pr_tftime; /* text page fault sleep time */ | |
| timestruc_64 pr_dftime; /* data page fault sleep time */ | |
| timestruc_64 pr_kftime; /* kernel page fault sleep time */ | |
| timestruc_64 pr_ltime; /* user lock wait sleep time */ | |
| timestruc_64 pr_slptime; /* all other sleep time */ | |
| timestruc_64 pr_wtime; /* wait-cpu (latency) time */ | |
| timestruc_64 pr_stoptime; /* stopped time */ | |
| timestruc_64 filltime[6]; /* filler for future expansion */ | |
| uint64_t pr_minf; /* minor page faults */ | |
| uint64_t pr_majf; /* major page faults */ | |
| uint64_t pr_nswap; /* swaps */ | |
| uint64_t pr_inblk; /* input blocks */ | |
| uint64_t pr_oublk; /* output blocks */ | |
| uint64_t pr_msnd; /* messages sent */ | |
| uint64_t pr_mrcv; /* messages received */ | |
| uint64_t pr_sigs; /* signals received */ | |
| uint64_t pr_vctx; /* voluntary context switches */ | |
| uint64_t pr_ictx; /* involuntary context switches */ | |
| uint64_t pr_sysc; /* system calls */ | |
| uint64_t pr_ioch; /* chars read and written */ | |
| uint64_t filler[10]; /* filler for future expansion */ | |
| } raw_prusage_64; | |
| uint64_t | |
| PrUsage::bind64Size () | |
| { | |
| uint64_t bindSize = sizeof (raw_prusage_64); | |
| return bindSize; | |
| } | |
| PrUsage * | |
| PrUsage::bind64 (void *p, bool need_swap_endian) | |
| { | |
| if (p == NULL) | |
| { | |
| return NULL; | |
| } | |
| raw_prusage_64 pu, *tmp = (raw_prusage_64*) p; | |
| if (need_swap_endian) | |
| { | |
| pu = *tmp; | |
| tmp = &pu; | |
| SWAP_ENDIAN (pu.pr_tstamp.tv_sec); | |
| SWAP_ENDIAN (pu.pr_tstamp.tv_nsec); | |
| SWAP_ENDIAN (pu.pr_create.tv_sec); | |
| SWAP_ENDIAN (pu.pr_create.tv_nsec); | |
| SWAP_ENDIAN (pu.pr_term.tv_sec); | |
| SWAP_ENDIAN (pu.pr_term.tv_nsec); | |
| SWAP_ENDIAN (pu.pr_rtime.tv_sec); | |
| SWAP_ENDIAN (pu.pr_rtime.tv_nsec); | |
| SWAP_ENDIAN (pu.pr_utime.tv_sec); | |
| SWAP_ENDIAN (pu.pr_utime.tv_nsec); | |
| SWAP_ENDIAN (pu.pr_stime.tv_sec); | |
| SWAP_ENDIAN (pu.pr_stime.tv_nsec); | |
| SWAP_ENDIAN (pu.pr_ttime.tv_sec); | |
| SWAP_ENDIAN (pu.pr_ttime.tv_nsec); | |
| SWAP_ENDIAN (pu.pr_tftime.tv_sec); | |
| SWAP_ENDIAN (pu.pr_tftime.tv_nsec); | |
| SWAP_ENDIAN (pu.pr_dftime.tv_sec); | |
| SWAP_ENDIAN (pu.pr_dftime.tv_nsec); | |
| SWAP_ENDIAN (pu.pr_kftime.tv_sec); | |
| SWAP_ENDIAN (pu.pr_kftime.tv_nsec); | |
| SWAP_ENDIAN (pu.pr_ltime.tv_sec); | |
| SWAP_ENDIAN (pu.pr_ltime.tv_nsec); | |
| SWAP_ENDIAN (pu.pr_slptime.tv_sec); | |
| SWAP_ENDIAN (pu.pr_slptime.tv_nsec); | |
| SWAP_ENDIAN (pu.pr_wtime.tv_sec); | |
| SWAP_ENDIAN (pu.pr_wtime.tv_nsec); | |
| SWAP_ENDIAN (pu.pr_stoptime.tv_sec); | |
| SWAP_ENDIAN (pu.pr_stoptime.tv_nsec); | |
| SWAP_ENDIAN (pu.pr_minf); | |
| SWAP_ENDIAN (pu.pr_majf); | |
| SWAP_ENDIAN (pu.pr_nswap); | |
| SWAP_ENDIAN (pu.pr_inblk); | |
| SWAP_ENDIAN (pu.pr_oublk); | |
| SWAP_ENDIAN (pu.pr_msnd); | |
| SWAP_ENDIAN (pu.pr_mrcv); | |
| SWAP_ENDIAN (pu.pr_sigs); | |
| SWAP_ENDIAN (pu.pr_vctx); | |
| SWAP_ENDIAN (pu.pr_ictx); | |
| SWAP_ENDIAN (pu.pr_sysc); | |
| SWAP_ENDIAN (pu.pr_ioch); | |
| } | |
| pr_tstamp = timestruc2hr (tmp->pr_tstamp); | |
| pr_create = timestruc2hr (tmp->pr_create); | |
| pr_term = timestruc2hr (tmp->pr_term); | |
| pr_rtime = timestruc2hr (tmp->pr_rtime); | |
| pr_utime = timestruc2hr (tmp->pr_utime); | |
| pr_stime = timestruc2hr (tmp->pr_stime); | |
| pr_ttime = timestruc2hr (tmp->pr_ttime); | |
| pr_tftime = timestruc2hr (tmp->pr_tftime); | |
| pr_dftime = timestruc2hr (tmp->pr_dftime); | |
| pr_kftime = timestruc2hr (tmp->pr_kftime); | |
| pr_ltime = timestruc2hr (tmp->pr_ltime); | |
| pr_slptime = timestruc2hr (tmp->pr_slptime); | |
| pr_wtime = timestruc2hr (tmp->pr_wtime); | |
| pr_stoptime = timestruc2hr (tmp->pr_stoptime); | |
| pr_minf = tmp->pr_minf; | |
| pr_majf = tmp->pr_majf; | |
| pr_nswap = tmp->pr_nswap; | |
| pr_inblk = tmp->pr_inblk; | |
| pr_oublk = tmp->pr_oublk; | |
| pr_msnd = tmp->pr_msnd; | |
| pr_mrcv = tmp->pr_mrcv; | |
| pr_sigs = tmp->pr_sigs; | |
| pr_vctx = tmp->pr_vctx; | |
| pr_ictx = tmp->pr_ictx; | |
| pr_sysc = tmp->pr_sysc; | |
| pr_ioch = tmp->pr_ioch; | |
| return this; | |
| } | |
| Vector<long long> * | |
| PrUsage::getMstateValues () | |
| { | |
| const PrUsage *prusage = this; | |
| Vector<long long> *states = new Vector<long long>; | |
| states->store (0, prusage->pr_utime); | |
| states->store (1, prusage->pr_stime); | |
| states->store (2, prusage->pr_ttime); | |
| states->store (3, prusage->pr_tftime); | |
| states->store (4, prusage->pr_dftime); | |
| states->store (5, prusage->pr_kftime); | |
| states->store (6, prusage->pr_ltime); | |
| states->store (7, prusage->pr_slptime); | |
| states->store (8, prusage->pr_wtime); | |
| states->store (9, prusage->pr_stoptime); | |
| assert (LMS_NUM_SOLARIS_MSTATES == states->size ()); | |
| return states; | |
| } | |
| void* CommonPacket::jvm_overhead = NULL; | |
| CommonPacket::CommonPacket () | |
| { | |
| for (int i = 0; i < NTAGS; i++) | |
| tags[i] = 0; | |
| tstamp = 0; | |
| jthread_TBR = NULL; | |
| frinfo = 0; | |
| leafpc = 0; | |
| nat_stack = NULL; | |
| user_stack = NULL; | |
| } | |
| int | |
| CommonPacket::cmp (const void *a, const void *b) | |
| { | |
| if ((*(CommonPacket **) a)->tstamp > (*(CommonPacket **) b)->tstamp) | |
| return 1; | |
| else if ((*(CommonPacket **) a)->tstamp < (*(CommonPacket **) b)->tstamp) | |
| return -1; | |
| else | |
| return 0; | |
| } | |
| void * | |
| CommonPacket::getStack (VMode view_mode) | |
| { | |
| if (view_mode == VMODE_MACHINE) | |
| return nat_stack; | |
| else if (view_mode == VMODE_USER) | |
| { | |
| if (jthread_TBR == JTHREAD_NONE || (jthread_TBR && jthread_TBR->is_system ())) | |
| return jvm_overhead; | |
| } | |
| else if (view_mode == VMODE_EXPERT) | |
| { | |
| Histable *hist = CallStack::getStackPC (user_stack, 0); | |
| if (hist->get_type () == Histable::INSTR) | |
| { | |
| DbeInstr *instr = (DbeInstr*) hist; | |
| if (instr->func == dbeSession->get_JUnknown_Function ()) | |
| return nat_stack; | |
| } | |
| else if (hist->get_type () == Histable::LINE) | |
| { | |
| DbeLine *line = (DbeLine *) hist; | |
| if (line->func == dbeSession->get_JUnknown_Function ()) | |
| return nat_stack; | |
| } | |
| } | |
| return user_stack; | |
| } | |
| Histable * | |
| CommonPacket::getStackPC (int n, VMode view_mode) | |
| { | |
| return CallStack::getStackPC (getStack (view_mode), n); | |
| } | |
| Vector<Histable*> * | |
| CommonPacket::getStackPCs (VMode view_mode) | |
| { | |
| return CallStack::getStackPCs (getStack (view_mode)); | |
| } | |
| void * | |
| getStack (VMode view_mode, DataView *dview, long idx) | |
| { | |
| void *stack = NULL; | |
| if (view_mode == VMODE_MACHINE) | |
| stack = dview->getObjValue (PROP_MSTACK, idx); | |
| else if (view_mode == VMODE_USER) | |
| stack = dview->getObjValue (PROP_USTACK, idx); | |
| else if (view_mode == VMODE_EXPERT) | |
| stack = dview->getObjValue (PROP_XSTACK, idx); | |
| return stack; | |
| } | |
| int | |
| stackSize (VMode view_mode, DataView *dview, long idx) | |
| { | |
| return CallStack::stackSize (getStack (view_mode, dview, idx)); | |
| } | |
| Histable * | |
| getStackPC (int n, VMode view_mode, DataView *dview, long idx) | |
| { | |
| return CallStack::getStackPC (getStack (view_mode, dview, idx), n); | |
| } | |
| Vector<Histable*> * | |
| getStackPCs (VMode view_mode, DataView *dview, long idx) | |
| { | |
| return CallStack::getStackPCs (getStack (view_mode, dview, idx)); | |
| } |