1/* Copyright (C) 2021 Free Software Foundation, Inc.
2   Contributed by Oracle.
3
4   This file is part of GNU Binutils.
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 3, or (at your option)
9   any later version.
10
11   This program is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with this program; if not, write to the Free Software
18   Foundation, 51 Franklin Street - Fifth Floor, Boston,
19   MA 02110-1301, USA.  */
20
21#include "config.h"
22#include <memory.h>
23#include <values.h>
24#include <assert.h>
25#include "Data_window.h"
26#include "Exp_Layout.h"
27#include "Table.h"
28#include "Ovw_data.h"
29#include "Sample.h"
30#include "data_pckts.h"
31#include "util.h"
32#include "i18n.h"
33
34void
35Ovw_data::sum (Ovw_data *data)
36{
37  Ovw_item data_totals = data->get_totals ();
38  if (totals == NULL)
39    {
40      totals = reset_item (new Ovw_item);
41      *totals = data_totals;
42      totals->start.tv_sec = totals->end.tv_sec = -1;
43      totals->start.tv_nsec = totals->end.tv_nsec = 0;
44    }
45  else
46    {
47      tsadd (&totals->duration, &data_totals.duration);
48      tsadd (&totals->tlwp, &data_totals.tlwp);
49      if (tstodouble (totals->duration) != 0)
50	totals->nlwp = tstodouble (totals->tlwp) / tstodouble (totals->duration);
51
52      for (int i = 0, size = totals->size; i < size; i++)
53	tsadd (&totals->values[i].t, &data_totals.values[i].t);
54    }
55}
56
57Ovw_data::Ovw_item *
58Ovw_data::reset_item (Ovw_data::Ovw_item *item)
59{
60  memset (item, 0, sizeof (*item));
61  return item;
62}
63
64Ovw_data::Ovw_item
65Ovw_data::get_totals ()
66{
67  // This routine will return the totals values for item in the sample.
68  // Compute maximums and totals only once, and save the result.
69  // On subsequent calls, just return the saved result.
70  // If maximums is NULL, then totals is also NULL
71  if (totals != NULL)
72    return *totals;
73
74  timestruc_t zero = {0, 0};
75  totals = reset_item (new Ovw_item);
76  totals->start.tv_sec = MAXINT; // new
77  totals->start.tv_nsec = MAXINT; // new
78  totals->start_label = totals->end_label = NTXT ("Total");
79  totals->type = VT_HRTIME;
80
81  int nsampsel = 0;
82  for (int index = 0; index < size (); index++)
83    {
84      Ovw_item item = fetch (index);
85      nsampsel++;
86
87      // Compute totals
88      for (int i = 0; i < OVW_NUMVALS + 1; i++)
89	tsadd (&totals->values[i].t, &item.values[i].t);
90
91      int_max (&totals->states, item.states);
92      tsadd (&totals->total.t, &item.total.t);
93      int_max (&totals->size, item.size);
94      tsadd (&totals->duration, &item.duration);
95      tsadd (&totals->tlwp, &item.tlwp);
96      totals->number += item.number;
97      if (tscmp (&totals->start, &item.start) > 0)
98	totals->start = item.start;
99      if (tscmp (&totals->end, &item.end) < 0)
100	totals->end = item.end;
101    }
102
103  if (totals->start.tv_sec == MAXINT && totals->start.tv_nsec == MAXINT)
104    totals->start = zero;
105  totals->nlwp = tstodouble (totals->tlwp) / tstodouble (totals->duration);
106
107  if (nsampsel == 0)
108    {
109      totals->size = OVW_NUMVALS + 1;
110      totals->start.tv_sec = totals->end.tv_sec = -1;
111      totals->start.tv_nsec = totals->end.tv_nsec = 0;
112      totals->nlwp = -1;
113    }
114  return *totals;
115}
116
117Ovw_data::Ovw_item
118Ovw_data::get_labels ()
119{
120  Ovw_item ovw_item;
121  Value *values;
122  memset (&ovw_item, 0, sizeof (Ovw_item));
123  values = &ovw_item.values[0];
124
125  char *stateUNames[/*LMS_NUM_STATES*/] = LMS_STATE_USTRINGS;
126  values[0].l = dbe_strdup (GTXT ("Leftover"));
127  values[OVW_LMS_USER + 1].l = stateUNames[LMS_USER];
128  values[OVW_LMS_SYSTEM + 1].l = stateUNames[LMS_SYSTEM];
129  values[OVW_LMS_WAIT_CPU + 1].l = stateUNames[LMS_WAIT_CPU];
130  values[OVW_LMS_USER_LOCK + 1].l = stateUNames[LMS_USER_LOCK];
131  values[OVW_LMS_TFAULT + 1].l = stateUNames[LMS_TFAULT];
132  values[OVW_LMS_DFAULT + 1].l = stateUNames[LMS_DFAULT];
133  values[OVW_LMS_KFAULT + 1].l = stateUNames[LMS_KFAULT];
134  values[OVW_LMS_SLEEP + 1].l = stateUNames[LMS_SLEEP];
135  values[OVW_LMS_STOPPED + 1].l = stateUNames[LMS_STOPPED];
136  values[OVW_LMS_TRAP + 1].l = stateUNames[LMS_TRAP];
137
138  ovw_item.size = OVW_NUMVALS + 1;
139  ovw_item.states = 0;
140  ovw_item.type = VT_LABEL;
141  return ovw_item;
142}
143
144Ovw_data::Ovw_data ()
145{
146  packets = NULL;
147  ovw_items = new Vector<Ovw_item*>;
148  totals = NULL;
149}
150
151Ovw_data::Ovw_data (DataView *_packets, hrtime_t exp_start)
152{
153  packets = _packets;
154  ovw_items = new Vector<Ovw_item*>;
155  totals = NULL;
156  long npackets = packets->getSize ();
157  for (long index = 0; index < npackets; index++)
158    {
159      Ovw_item *ovw_item = new Ovw_item;
160      memset (ovw_item, 0, sizeof (Ovw_item));
161      Sample *sample = (Sample*) packets->getObjValue (PROP_SMPLOBJ, index);
162      extract_data (ovw_item, sample);
163      hr2timestruc (&ovw_item->start, sample->get_start_time () - exp_start);
164      hr2timestruc (&ovw_item->end, sample->get_end_time () - exp_start);
165      //  No need to check for duration, as duration has to be > 0.
166      //  If not, it would have been found out in yyparse.
167      tssub (&ovw_item->duration, &ovw_item->end, &ovw_item->start);
168      ovw_item->number = sample->get_number ();
169      ovw_item->start_label = sample->get_start_label ();
170      ovw_item->end_label = sample->get_end_label ();
171
172      int size = ovw_item->size;
173      for (int j = 0; j < size; j++)
174	tsadd (&ovw_item->tlwp, &ovw_item->values[j].t);
175      if (tstodouble (ovw_item->duration) != 0)
176	ovw_item->nlwp = tstodouble (ovw_item->tlwp) /
177		tstodouble (ovw_item->duration);
178      ovw_items->append (ovw_item);
179    }
180}
181
182Ovw_data::~Ovw_data ()
183{
184  ovw_items->destroy ();
185  delete ovw_items;
186  delete totals;
187}
188
189void
190Ovw_data::extract_data (Ovw_data::Ovw_item *ovw_item, Sample *sample)
191{
192  // This routine break out the data in "data" into buckets in "ovw_item"
193  int index;
194  int states;
195  timestruc_t sum, rtime;
196  timestruc_t zero = {0, 0};
197  Value *values;
198  PrUsage *prusage = sample->get_usage ();
199  if (prusage == NULL)
200    prusage = new PrUsage;
201
202  values = &ovw_item->values[0];
203  hr2timestruc (&values[OVW_LMS_USER + 1].t, prusage->pr_utime);
204  hr2timestruc (&values[OVW_LMS_SYSTEM + 1].t, prusage->pr_stime);
205  hr2timestruc (&values[OVW_LMS_WAIT_CPU + 1].t, prusage->pr_wtime);
206  hr2timestruc (&values[OVW_LMS_USER_LOCK + 1].t, prusage->pr_ltime);
207  hr2timestruc (&values[OVW_LMS_TFAULT + 1].t, prusage->pr_tftime);
208  hr2timestruc (&values[OVW_LMS_DFAULT + 1].t, prusage->pr_dftime);
209  hr2timestruc (&values[OVW_LMS_TRAP + 1].t, prusage->pr_ttime);
210  hr2timestruc (&values[OVW_LMS_KFAULT + 1].t, prusage->pr_kftime);
211  hr2timestruc (&values[OVW_LMS_SLEEP + 1].t, prusage->pr_slptime);
212  hr2timestruc (&values[OVW_LMS_STOPPED + 1].t, prusage->pr_stoptime);
213  ovw_item->size = OVW_NUMVALS + 1;
214
215  //XXX: Compute values[0] as rtime - sum_of(other_times)
216  sum = zero;
217  states = 0;
218  for (index = 1; index < ovw_item->size; index++)
219    {
220      if (values[index].t.tv_sec != 0 || values[index].t.tv_nsec != 0)
221	states++;
222      tsadd (&sum, &values[index].t);
223    }
224
225  //  If the sum of all times is greater than rtime then adjust
226  //  rtime to be equal to sum and also adjust the pr_rtime field
227  hr2timestruc (&rtime, prusage->pr_rtime);
228  if (tscmp (&sum, &rtime) > 0)
229    {
230      ovw_item->total.t = sum;
231      values[0].t = zero;
232    }
233  else
234    {
235      ovw_item->total.t = rtime;
236      tssub (&rtime, &rtime, &sum);
237      tsadd (&values[0].t, &rtime);
238      states++;
239    }
240  ovw_item->type = VT_HRTIME;
241  ovw_item->states = states;
242}
243