Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/hotspot/os/linux/os_perf_linux.cpp
40951 views
1
/*
2
* Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation.
8
*
9
* This code is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12
* version 2 for more details (a copy is included in the LICENSE file that
13
* accompanied this code).
14
*
15
* You should have received a copy of the GNU General Public License version
16
* 2 along with this work; if not, write to the Free Software Foundation,
17
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
*
19
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
* or visit www.oracle.com if you need additional information or have any
21
* questions.
22
*
23
*/
24
25
#include "precompiled.hpp"
26
#include "jvm.h"
27
#include "memory/allocation.inline.hpp"
28
#include "os_linux.inline.hpp"
29
#include "runtime/os.hpp"
30
#include "runtime/os_perf.hpp"
31
#include "utilities/globalDefinitions.hpp"
32
33
#include CPU_HEADER(vm_version_ext)
34
35
#include <stdio.h>
36
#include <stdarg.h>
37
#include <unistd.h>
38
#include <errno.h>
39
#include <string.h>
40
#include <sys/resource.h>
41
#include <sys/types.h>
42
#include <sys/stat.h>
43
#include <dirent.h>
44
#include <stdlib.h>
45
#include <dlfcn.h>
46
#include <pthread.h>
47
#include <limits.h>
48
#ifndef __ANDROID__
49
#include <ifaddrs.h>
50
#else
51
#include <sys/cdefs.h>
52
#include <netinet/in.h>
53
#include <sys/socket.h>
54
#include <linux/if_packet.h>
55
#include <linux/netlink.h>
56
#include <linux/rtnetlink.h>
57
#include <net/if.h>
58
#include <stdint.h>
59
#endif
60
#include <fcntl.h>
61
62
#ifdef __ANDROID__
63
/*
64
* Copyright (C) 2015 The Android Open Source Project
65
* All rights reserved.
66
*
67
* Redistribution and use in source and binary forms, with or without
68
* modification, are permitted provided that the following conditions
69
* are met:
70
* * Redistributions of source code must retain the above copyright
71
* notice, this list of conditions and the following disclaimer.
72
* * Redistributions in binary form must reproduce the above copyright
73
* notice, this list of conditions and the following disclaimer in
74
* the documentation and/or other materials provided with the
75
* distribution.
76
*
77
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
78
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
79
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
80
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
81
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
82
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
83
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
84
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
85
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
86
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
87
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
88
* SUCH DAMAGE.
89
*/
90
91
__BEGIN_DECLS
92
93
/**
94
* Returned by getifaddrs() and freed by freeifaddrs().
95
*/
96
struct ifaddrs {
97
/** Pointer to the next element in the linked list. */
98
struct ifaddrs* ifa_next;
99
100
/** Interface name. */
101
char* ifa_name;
102
103
/** Interface flags (like `SIOCGIFFLAGS`). */
104
unsigned int ifa_flags;
105
106
/** Interface address. */
107
struct sockaddr* ifa_addr;
108
109
/** Interface netmask. */
110
struct sockaddr* ifa_netmask;
111
112
union {
113
/** Interface broadcast address (if IFF_BROADCAST is set). */
114
struct sockaddr* ifu_broadaddr;
115
116
/** Interface destination address (if IFF_POINTOPOINT is set). */
117
struct sockaddr* ifu_dstaddr;
118
} ifa_ifu;
119
120
/** Unused. */
121
void* ifa_data;
122
};
123
124
/** Synonym for `ifa_ifu.ifu_broadaddr` in `struct ifaddrs`. */
125
#define ifa_broadaddr ifa_ifu.ifu_broadaddr
126
127
/** Synonym for `ifa_ifu.ifu_dstaddr` in `struct ifaddrs`. */
128
#define ifa_dstaddr ifa_ifu.ifu_dstaddr
129
130
/**
131
* [getifaddrs(3)](http://man7.org/linux/man-pages/man3/getifaddrs.3.html) creates a linked list
132
* of `struct ifaddrs`. The list must be freed by freeifaddrs().
133
*
134
* Returns 0 and stores the list in `*__list_ptr` on success,
135
* and returns -1 and sets `errno` on failure.
136
*
137
* Available since API level 24.
138
*/
139
int getifaddrs(struct ifaddrs** __list_ptr); // __INTRODUCED_IN(24);
140
141
/**
142
* [freeifaddrs(3)](http://man7.org/linux/man-pages/man3/freeifaddrs.3.html) frees a linked list
143
* of `struct ifaddrs` returned by getifaddrs().
144
*
145
* Available since API level 24.
146
*/
147
void freeifaddrs(struct ifaddrs* __ptr); // __INTRODUCED_IN(24);
148
149
__END_DECLS
150
151
#define nullptr 0
152
153
// The public ifaddrs struct is full of pointers. Rather than track several
154
// different allocations, we use a maximally-sized structure with the public
155
// part at offset 0, and pointers into its hidden tail.
156
struct ifaddrs_storage {
157
// Must come first, so that `ifaddrs_storage` is-a `ifaddrs`.
158
ifaddrs ifa;
159
// The interface index, so we can match RTM_NEWADDR messages with
160
// earlier RTM_NEWLINK messages (to copy the interface flags).
161
int interface_index;
162
// Storage for the pointers in `ifa`.
163
sockaddr_storage addr;
164
sockaddr_storage netmask;
165
sockaddr_storage ifa_ifu;
166
char name[IFNAMSIZ + 1];
167
// Netlink gives us the address family in the header, and the
168
// sockaddr_in or sockaddr_in6 bytes as the payload. We need to
169
// stitch the two bits together into the sockaddr that's part of
170
// our portable interface.
171
void SetAddress(int family, const void* data, size_t byteCount) {
172
addr.ss_family = family;
173
memcpy(SockaddrBytes(family, &addr), data, byteCount);
174
ifa.ifa_addr = reinterpret_cast<sockaddr*>(&addr);
175
}
176
void SetBroadcastAddress(int family, const void* data, size_t byteCount) {
177
ifa_ifu.ss_family = family;
178
memcpy(SockaddrBytes(family, &ifa_ifu), data, byteCount);
179
ifa.ifa_dstaddr = reinterpret_cast<sockaddr*>(&ifa_ifu);
180
}
181
// Netlink gives us the prefix length as a bit count. We need to turn
182
// that into a BSD-compatible netmask represented by a sockaddr*.
183
void SetNetmask(int family, size_t prefix_length) {
184
// ...and work out the netmask from the prefix length.
185
netmask.ss_family = family;
186
uint8_t* dst = SockaddrBytes(family, &netmask);
187
memset(dst, 0xff, prefix_length / 8);
188
if ((prefix_length % 8) != 0) {
189
dst[prefix_length/8] = (0xff << (8 - (prefix_length % 8)));
190
}
191
ifa.ifa_netmask = reinterpret_cast<sockaddr*>(&netmask);
192
}
193
void SetPacketAttributes(int ifindex, unsigned short hatype, unsigned char halen) {
194
sockaddr_ll* sll = reinterpret_cast<sockaddr_ll*>(&addr);
195
sll->sll_ifindex = ifindex;
196
sll->sll_hatype = hatype;
197
sll->sll_halen = halen;
198
}
199
private:
200
// Returns a pointer to the first byte in the address data (which is
201
// stored in network byte order).
202
uint8_t* SockaddrBytes(int family, sockaddr_storage* ss) {
203
if (family == AF_INET) {
204
sockaddr_in* ss4 = reinterpret_cast<sockaddr_in*>(ss);
205
return reinterpret_cast<uint8_t*>(&ss4->sin_addr);
206
} else if (family == AF_INET6) {
207
sockaddr_in6* ss6 = reinterpret_cast<sockaddr_in6*>(ss);
208
return reinterpret_cast<uint8_t*>(&ss6->sin6_addr);
209
} else if (family == AF_PACKET) {
210
sockaddr_ll* sll = reinterpret_cast<sockaddr_ll*>(ss);
211
return reinterpret_cast<uint8_t*>(&sll->sll_addr);
212
}
213
return nullptr;
214
}
215
};
216
ifaddrs_storage* new_ifaddrs_storage(ifaddrs** list) {
217
ifaddrs_storage *storage;
218
memset(storage, 0, sizeof(*storage));
219
// push_front onto `list`.
220
storage->ifa.ifa_next = *list;
221
*list = reinterpret_cast<ifaddrs*>(storage);
222
return storage;
223
}
224
#if !defined(__clang__)
225
// GCC gets confused by NLMSG_DATA and doesn't realize that the old-style
226
// cast is from a system header and should be ignored.
227
#pragma GCC diagnostic ignored "-Wold-style-cast"
228
#endif
229
static void __handle_netlink_response(ifaddrs** out, nlmsghdr* hdr) {
230
if (hdr->nlmsg_type == RTM_NEWLINK) {
231
ifinfomsg* ifi = reinterpret_cast<ifinfomsg*>(NLMSG_DATA(hdr));
232
// Create a new ifaddr entry, and set the interface index and flags.
233
ifaddrs_storage* new_addr = new_ifaddrs_storage(out);
234
new_addr->interface_index = ifi->ifi_index;
235
new_addr->ifa.ifa_flags = ifi->ifi_flags;
236
// Go through the various bits of information and find the name.
237
rtattr* rta = IFLA_RTA(ifi);
238
size_t rta_len = IFLA_PAYLOAD(hdr);
239
while (RTA_OK(rta, rta_len)) {
240
if (rta->rta_type == IFLA_ADDRESS) {
241
if (RTA_PAYLOAD(rta) < sizeof(new_addr->addr)) {
242
new_addr->SetAddress(AF_PACKET, RTA_DATA(rta), RTA_PAYLOAD(rta));
243
new_addr->SetPacketAttributes(ifi->ifi_index, ifi->ifi_type, RTA_PAYLOAD(rta));
244
}
245
} else if (rta->rta_type == IFLA_BROADCAST) {
246
if (RTA_PAYLOAD(rta) < sizeof(new_addr->ifa_ifu)) {
247
new_addr->SetBroadcastAddress(AF_PACKET, RTA_DATA(rta), RTA_PAYLOAD(rta));
248
new_addr->SetPacketAttributes(ifi->ifi_index, ifi->ifi_type, RTA_PAYLOAD(rta));
249
}
250
} else if (rta->rta_type == IFLA_IFNAME) {
251
if (RTA_PAYLOAD(rta) < sizeof(new_addr->name)) {
252
memcpy(new_addr->name, RTA_DATA(rta), RTA_PAYLOAD(rta));
253
new_addr->ifa.ifa_name = new_addr->name;
254
}
255
}
256
rta = RTA_NEXT(rta, rta_len);
257
}
258
} else if (hdr->nlmsg_type == RTM_NEWADDR) {
259
ifaddrmsg* msg = reinterpret_cast<ifaddrmsg*>(NLMSG_DATA(hdr));
260
// We should already know about this from an RTM_NEWLINK message.
261
const ifaddrs_storage* addr = reinterpret_cast<const ifaddrs_storage*>(*out);
262
while (addr != nullptr && addr->interface_index != static_cast<int>(msg->ifa_index)) {
263
addr = reinterpret_cast<const ifaddrs_storage*>(addr->ifa.ifa_next);
264
}
265
// If this is an unknown interface, ignore whatever we're being told about it.
266
if (addr == nullptr) return;
267
// Create a new ifaddr entry and copy what we already know.
268
ifaddrs_storage* new_addr = new_ifaddrs_storage(out);
269
// We can just copy the name rather than look for IFA_LABEL.
270
strcpy(new_addr->name, addr->name);
271
new_addr->ifa.ifa_name = new_addr->name;
272
new_addr->ifa.ifa_flags = addr->ifa.ifa_flags;
273
new_addr->interface_index = addr->interface_index;
274
// Go through the various bits of information and find the address
275
// and any broadcast/destination address.
276
rtattr* rta = IFA_RTA(msg);
277
size_t rta_len = IFA_PAYLOAD(hdr);
278
while (RTA_OK(rta, rta_len)) {
279
if (rta->rta_type == IFA_ADDRESS) {
280
if (msg->ifa_family == AF_INET || msg->ifa_family == AF_INET6) {
281
new_addr->SetAddress(msg->ifa_family, RTA_DATA(rta), RTA_PAYLOAD(rta));
282
new_addr->SetNetmask(msg->ifa_family, msg->ifa_prefixlen);
283
}
284
} else if (rta->rta_type == IFA_BROADCAST) {
285
if (msg->ifa_family == AF_INET || msg->ifa_family == AF_INET6) {
286
new_addr->SetBroadcastAddress(msg->ifa_family, RTA_DATA(rta), RTA_PAYLOAD(rta));
287
}
288
}
289
rta = RTA_NEXT(rta, rta_len);
290
}
291
}
292
}
293
static bool __send_netlink_request(int fd, int type) {
294
struct NetlinkMessage {
295
nlmsghdr hdr;
296
rtgenmsg msg;
297
} request;
298
memset(&request, 0, sizeof(request));
299
request.hdr.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
300
request.hdr.nlmsg_type = type;
301
request.hdr.nlmsg_len = sizeof(request);
302
request.msg.rtgen_family = AF_UNSPEC; // All families.
303
return (TEMP_FAILURE_RETRY(send(fd, &request, sizeof(request), 0)) == sizeof(request));
304
}
305
static bool __read_netlink_responses(int fd, ifaddrs** out, char* buf, size_t buf_len) {
306
ssize_t bytes_read;
307
// Read through all the responses, handing interesting ones to __handle_netlink_response.
308
while ((bytes_read = TEMP_FAILURE_RETRY(recv(fd, buf, buf_len, 0))) > 0) {
309
nlmsghdr* hdr = reinterpret_cast<nlmsghdr*>(buf);
310
for (; NLMSG_OK(hdr, static_cast<size_t>(bytes_read)); hdr = NLMSG_NEXT(hdr, bytes_read)) {
311
if (hdr->nlmsg_type == NLMSG_DONE) return true;
312
if (hdr->nlmsg_type == NLMSG_ERROR) return false;
313
__handle_netlink_response(out, hdr);
314
}
315
}
316
// We only get here if recv fails before we see a NLMSG_DONE.
317
return false;
318
}
319
int getifaddrs(ifaddrs** out) {
320
// Make cleanup easy.
321
*out = nullptr;
322
// The kernel keeps packets under 8KiB (NLMSG_GOODSIZE),
323
// but that's a bit too large to go on the stack.
324
size_t buf_len = 8192;
325
char* buf = NEW_C_HEAP_ARRAY(char, buf_len, mtInternal);
326
if (buf == nullptr) return -1;
327
// Open the netlink socket and ask for all the links and addresses.
328
int fd = socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
329
bool okay = fd != -1 &&
330
__send_netlink_request(fd, RTM_GETLINK) && __read_netlink_responses(fd, out, buf, buf_len) &&
331
__send_netlink_request(fd, RTM_GETADDR) && __read_netlink_responses(fd, out, buf, buf_len);
332
if (!okay) {
333
freeifaddrs(*out);
334
// Ensure that callers crash if they forget to check for success.
335
*out = nullptr;
336
}
337
{
338
int saved_errno = errno;
339
close(fd);
340
FREE_C_HEAP_ARRAY(char, buf);
341
errno = saved_errno;
342
}
343
return okay ? 0 : -1;
344
}
345
void freeifaddrs(ifaddrs* list) {
346
while (list != nullptr) {
347
ifaddrs* current = list;
348
list = list->ifa_next;
349
free(current);
350
}
351
}
352
#endif
353
354
/**
355
/proc/[number]/stat
356
Status information about the process. This is used by ps(1). It is defined in /usr/src/linux/fs/proc/array.c.
357
358
The fields, in order, with their proper scanf(3) format specifiers, are:
359
360
1. pid %d The process id.
361
362
2. comm %s
363
The filename of the executable, in parentheses. This is visible whether or not the executable is swapped out.
364
365
3. state %c
366
One character from the string "RSDZTW" where R is running, S is sleeping in an interruptible wait, D is waiting in uninterruptible disk
367
sleep, Z is zombie, T is traced or stopped (on a signal), and W is paging.
368
369
4. ppid %d
370
The PID of the parent.
371
372
5. pgrp %d
373
The process group ID of the process.
374
375
6. session %d
376
The session ID of the process.
377
378
7. tty_nr %d
379
The tty the process uses.
380
381
8. tpgid %d
382
The process group ID of the process which currently owns the tty that the process is connected to.
383
384
9. flags %lu
385
The flags of the process. The math bit is decimal 4, and the traced bit is decimal 10.
386
387
10. minflt %lu
388
The number of minor faults the process has made which have not required loading a memory page from disk.
389
390
11. cminflt %lu
391
The number of minor faults that the process's waited-for children have made.
392
393
12. majflt %lu
394
The number of major faults the process has made which have required loading a memory page from disk.
395
396
13. cmajflt %lu
397
The number of major faults that the process's waited-for children have made.
398
399
14. utime %lu
400
The number of jiffies that this process has been scheduled in user mode.
401
402
15. stime %lu
403
The number of jiffies that this process has been scheduled in kernel mode.
404
405
16. cutime %ld
406
The number of jiffies that this process's waited-for children have been scheduled in user mode. (See also times(2).)
407
408
17. cstime %ld
409
The number of jiffies that this process' waited-for children have been scheduled in kernel mode.
410
411
18. priority %ld
412
The standard nice value, plus fifteen. The value is never negative in the kernel.
413
414
19. nice %ld
415
The nice value ranges from 19 (nicest) to -19 (not nice to others).
416
417
20. 0 %ld This value is hard coded to 0 as a placeholder for a removed field.
418
419
21. itrealvalue %ld
420
The time in jiffies before the next SIGALRM is sent to the process due to an interval timer.
421
422
22. starttime %lu
423
The time in jiffies the process started after system boot.
424
425
23. vsize %lu
426
Virtual memory size in bytes.
427
428
24. rss %ld
429
Resident Set Size: number of pages the process has in real memory, minus 3 for administrative purposes. This is just the pages which count
430
towards text, data, or stack space. This does not include pages which have not been demand-loaded in, or which are swapped out.
431
432
25. rlim %lu
433
Current limit in bytes on the rss of the process (usually 4294967295 on i386).
434
435
26. startcode %lu
436
The address above which program text can run.
437
438
27. endcode %lu
439
The address below which program text can run.
440
441
28. startstack %lu
442
The address of the start of the stack.
443
444
29. kstkesp %lu
445
The current value of esp (stack pointer), as found in the kernel stack page for the process.
446
447
30. kstkeip %lu
448
The current EIP (instruction pointer).
449
450
31. signal %lu
451
The bitmap of pending signals (usually 0).
452
453
32. blocked %lu
454
The bitmap of blocked signals (usually 0, 2 for shells).
455
456
33. sigignore %lu
457
The bitmap of ignored signals.
458
459
34. sigcatch %lu
460
The bitmap of catched signals.
461
462
35. wchan %lu
463
This is the "channel" in which the process is waiting. It is the address of a system call, and can be looked up in a namelist if you need
464
a textual name. (If you have an up-to-date /etc/psdatabase, then try ps -l to see the WCHAN field in action.)
465
466
36. nswap %lu
467
Number of pages swapped - not maintained.
468
469
37. cnswap %lu
470
Cumulative nswap for child processes.
471
472
38. exit_signal %d
473
Signal to be sent to parent when we die.
474
475
39. processor %d
476
CPU number last executed on.
477
478
479
480
///// SSCANF FORMAT STRING. Copy and use.
481
482
field: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
483
format: %d %s %c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %d %d
484
485
486
*/
487
488
/**
489
* For platforms that have them, when declaring
490
* a printf-style function,
491
* formatSpec is the parameter number (starting at 1)
492
* that is the format argument ("%d pid %s")
493
* params is the parameter number where the actual args to
494
* the format starts. If the args are in a va_list, this
495
* should be 0.
496
*/
497
#ifndef PRINTF_ARGS
498
# define PRINTF_ARGS(formatSpec, params) ATTRIBUTE_PRINTF(formatSpec, params)
499
#endif
500
501
#ifndef SCANF_ARGS
502
# define SCANF_ARGS(formatSpec, params) ATTRIBUTE_SCANF(formatSpec, params)
503
#endif
504
505
#ifndef _PRINTFMT_
506
# define _PRINTFMT_
507
#endif
508
509
#ifndef _SCANFMT_
510
# define _SCANFMT_
511
#endif
512
513
typedef enum {
514
CPU_LOAD_VM_ONLY,
515
CPU_LOAD_GLOBAL,
516
} CpuLoadTarget;
517
518
enum {
519
UNDETECTED,
520
UNDETECTABLE,
521
LINUX26_NPTL,
522
BAREMETAL
523
};
524
525
struct CPUPerfCounters {
526
int nProcs;
527
os::Linux::CPUPerfTicks jvmTicks;
528
os::Linux::CPUPerfTicks* cpus;
529
};
530
531
static double get_cpu_load(int which_logical_cpu, CPUPerfCounters* counters, double* pkernelLoad, CpuLoadTarget target);
532
533
/** reads /proc/<pid>/stat data, with some checks and some skips.
534
* Ensure that 'fmt' does _NOT_ contain the first two "%d %s"
535
*/
536
static int SCANF_ARGS(2, 0) vread_statdata(const char* procfile, _SCANFMT_ const char* fmt, va_list args) {
537
FILE*f;
538
int n;
539
char buf[2048];
540
541
if ((f = fopen(procfile, "r")) == NULL) {
542
return -1;
543
}
544
545
if ((n = fread(buf, 1, sizeof(buf), f)) != -1) {
546
char *tmp;
547
548
buf[n-1] = '\0';
549
/** skip through pid and exec name. */
550
if ((tmp = strrchr(buf, ')')) != NULL) {
551
// skip the ')' and the following space
552
// but check that buffer is long enough
553
tmp += 2;
554
if (tmp < buf + n) {
555
n = vsscanf(tmp, fmt, args);
556
}
557
}
558
}
559
560
fclose(f);
561
562
return n;
563
}
564
565
static int SCANF_ARGS(2, 3) read_statdata(const char* procfile, _SCANFMT_ const char* fmt, ...) {
566
int n;
567
va_list args;
568
569
va_start(args, fmt);
570
n = vread_statdata(procfile, fmt, args);
571
va_end(args);
572
return n;
573
}
574
575
static FILE* open_statfile(void) {
576
FILE *f;
577
578
if ((f = fopen("/proc/stat", "r")) == NULL) {
579
static int haveWarned = 0;
580
if (!haveWarned) {
581
haveWarned = 1;
582
}
583
}
584
return f;
585
}
586
587
static int get_systemtype(void) {
588
static int procEntriesType = UNDETECTED;
589
DIR *taskDir;
590
591
if (procEntriesType != UNDETECTED) {
592
return procEntriesType;
593
}
594
595
// Check whether we have a task subdirectory
596
if ((taskDir = opendir("/proc/self/task")) == NULL) {
597
procEntriesType = UNDETECTABLE;
598
} else {
599
// The task subdirectory exists; we're on a Linux >= 2.6 system
600
closedir(taskDir);
601
procEntriesType = LINUX26_NPTL;
602
}
603
604
return procEntriesType;
605
}
606
607
/** read user and system ticks from a named procfile, assumed to be in 'stat' format then. */
608
static int read_ticks(const char* procfile, uint64_t* userTicks, uint64_t* systemTicks) {
609
return read_statdata(procfile, "%*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u " UINT64_FORMAT " " UINT64_FORMAT,
610
userTicks, systemTicks);
611
}
612
613
/**
614
* Return the number of ticks spent in any of the processes belonging
615
* to the JVM on any CPU.
616
*/
617
static OSReturn get_jvm_ticks(os::Linux::CPUPerfTicks* pticks) {
618
uint64_t userTicks;
619
uint64_t systemTicks;
620
621
if (get_systemtype() != LINUX26_NPTL) {
622
return OS_ERR;
623
}
624
625
if (read_ticks("/proc/self/stat", &userTicks, &systemTicks) != 2) {
626
return OS_ERR;
627
}
628
629
// get the total
630
if (! os::Linux::get_tick_information(pticks, -1)) {
631
return OS_ERR;
632
}
633
634
pticks->used = userTicks;
635
pticks->usedKernel = systemTicks;
636
637
return OS_OK;
638
}
639
640
/**
641
* Return the load of the CPU as a double. 1.0 means the CPU process uses all
642
* available time for user or system processes, 0.0 means the CPU uses all time
643
* being idle.
644
*
645
* Returns a negative value if there is a problem in determining the CPU load.
646
*/
647
static double get_cpu_load(int which_logical_cpu, CPUPerfCounters* counters, double* pkernelLoad, CpuLoadTarget target) {
648
uint64_t udiff, kdiff, tdiff;
649
os::Linux::CPUPerfTicks* pticks;
650
os::Linux::CPUPerfTicks tmp;
651
double user_load;
652
653
*pkernelLoad = 0.0;
654
655
if (target == CPU_LOAD_VM_ONLY) {
656
pticks = &counters->jvmTicks;
657
} else if (-1 == which_logical_cpu) {
658
pticks = &counters->cpus[counters->nProcs];
659
} else {
660
pticks = &counters->cpus[which_logical_cpu];
661
}
662
663
tmp = *pticks;
664
665
if (target == CPU_LOAD_VM_ONLY) {
666
if (get_jvm_ticks(pticks) != OS_OK) {
667
return -1.0;
668
}
669
} else if (! os::Linux::get_tick_information(pticks, which_logical_cpu)) {
670
return -1.0;
671
}
672
673
// seems like we sometimes end up with less kernel ticks when
674
// reading /proc/self/stat a second time, timing issue between cpus?
675
if (pticks->usedKernel < tmp.usedKernel) {
676
kdiff = 0;
677
} else {
678
kdiff = pticks->usedKernel - tmp.usedKernel;
679
}
680
tdiff = pticks->total - tmp.total;
681
udiff = pticks->used - tmp.used;
682
683
if (tdiff == 0) {
684
return 0.0;
685
} else if (tdiff < (udiff + kdiff)) {
686
tdiff = udiff + kdiff;
687
}
688
*pkernelLoad = (kdiff / (double)tdiff);
689
// BUG9044876, normalize return values to sane values
690
*pkernelLoad = MAX2<double>(*pkernelLoad, 0.0);
691
*pkernelLoad = MIN2<double>(*pkernelLoad, 1.0);
692
693
user_load = (udiff / (double)tdiff);
694
user_load = MAX2<double>(user_load, 0.0);
695
user_load = MIN2<double>(user_load, 1.0);
696
697
return user_load;
698
}
699
700
static int SCANF_ARGS(1, 2) parse_stat(_SCANFMT_ const char* fmt, ...) {
701
FILE *f;
702
va_list args;
703
704
va_start(args, fmt);
705
706
if ((f = open_statfile()) == NULL) {
707
va_end(args);
708
return OS_ERR;
709
}
710
for (;;) {
711
char line[80];
712
if (fgets(line, sizeof(line), f) != NULL) {
713
if (vsscanf(line, fmt, args) == 1) {
714
fclose(f);
715
va_end(args);
716
return OS_OK;
717
}
718
} else {
719
fclose(f);
720
va_end(args);
721
return OS_ERR;
722
}
723
}
724
}
725
726
static int get_noof_context_switches(uint64_t* switches) {
727
return parse_stat("ctxt " UINT64_FORMAT "\n", switches);
728
}
729
730
/** returns boot time in _seconds_ since epoch */
731
static int get_boot_time(uint64_t* time) {
732
return parse_stat("btime " UINT64_FORMAT "\n", time);
733
}
734
735
static int perf_context_switch_rate(double* rate) {
736
static pthread_mutex_t contextSwitchLock = PTHREAD_MUTEX_INITIALIZER;
737
static uint64_t bootTime;
738
static uint64_t lastTimeNanos;
739
static uint64_t lastSwitches;
740
static double lastRate;
741
742
uint64_t bt = 0;
743
int res = 0;
744
745
// First time through bootTime will be zero.
746
if (bootTime == 0) {
747
uint64_t tmp;
748
if (get_boot_time(&tmp) < 0) {
749
return OS_ERR;
750
}
751
bt = tmp * 1000;
752
}
753
754
res = OS_OK;
755
756
pthread_mutex_lock(&contextSwitchLock);
757
{
758
759
uint64_t sw;
760
s8 t, d;
761
762
if (bootTime == 0) {
763
// First interval is measured from boot time which is
764
// seconds since the epoch. Thereafter we measure the
765
// elapsed time using javaTimeNanos as it is monotonic-
766
// non-decreasing.
767
lastTimeNanos = os::javaTimeNanos();
768
t = os::javaTimeMillis();
769
d = t - bt;
770
// keep bootTime zero for now to use as a first-time-through flag
771
} else {
772
t = os::javaTimeNanos();
773
d = nanos_to_millis(t - lastTimeNanos);
774
}
775
776
if (d == 0) {
777
*rate = lastRate;
778
} else if (get_noof_context_switches(&sw) == 0) {
779
*rate = ( (double)(sw - lastSwitches) / d ) * 1000;
780
lastRate = *rate;
781
lastSwitches = sw;
782
if (bootTime != 0) {
783
lastTimeNanos = t;
784
}
785
} else {
786
*rate = 0;
787
res = OS_ERR;
788
}
789
if (*rate <= 0) {
790
*rate = 0;
791
lastRate = 0;
792
}
793
794
if (bootTime == 0) {
795
bootTime = bt;
796
}
797
}
798
pthread_mutex_unlock(&contextSwitchLock);
799
800
return res;
801
}
802
803
class CPUPerformanceInterface::CPUPerformance : public CHeapObj<mtInternal> {
804
friend class CPUPerformanceInterface;
805
private:
806
CPUPerfCounters _counters;
807
808
int cpu_load(int which_logical_cpu, double* cpu_load);
809
int context_switch_rate(double* rate);
810
int cpu_load_total_process(double* cpu_load);
811
int cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad);
812
813
public:
814
CPUPerformance();
815
bool initialize();
816
~CPUPerformance();
817
};
818
819
CPUPerformanceInterface::CPUPerformance::CPUPerformance() {
820
_counters.nProcs = os::active_processor_count();
821
_counters.cpus = NULL;
822
}
823
824
bool CPUPerformanceInterface::CPUPerformance::initialize() {
825
size_t array_entry_count = _counters.nProcs + 1;
826
_counters.cpus = NEW_C_HEAP_ARRAY(os::Linux::CPUPerfTicks, array_entry_count, mtInternal);
827
memset(_counters.cpus, 0, array_entry_count * sizeof(*_counters.cpus));
828
829
// For the CPU load total
830
os::Linux::get_tick_information(&_counters.cpus[_counters.nProcs], -1);
831
832
// For each CPU
833
for (int i = 0; i < _counters.nProcs; i++) {
834
os::Linux::get_tick_information(&_counters.cpus[i], i);
835
}
836
// For JVM load
837
get_jvm_ticks(&_counters.jvmTicks);
838
839
// initialize context switch system
840
// the double is only for init
841
double init_ctx_switch_rate;
842
perf_context_switch_rate(&init_ctx_switch_rate);
843
844
return true;
845
}
846
847
CPUPerformanceInterface::CPUPerformance::~CPUPerformance() {
848
if (_counters.cpus != NULL) {
849
FREE_C_HEAP_ARRAY(char, _counters.cpus);
850
}
851
}
852
853
int CPUPerformanceInterface::CPUPerformance::cpu_load(int which_logical_cpu, double* cpu_load) {
854
double u, s;
855
u = get_cpu_load(which_logical_cpu, &_counters, &s, CPU_LOAD_GLOBAL);
856
if (u < 0) {
857
*cpu_load = 0.0;
858
return OS_ERR;
859
}
860
// Cap total systemload to 1.0
861
*cpu_load = MIN2<double>((u + s), 1.0);
862
return OS_OK;
863
}
864
865
int CPUPerformanceInterface::CPUPerformance::cpu_load_total_process(double* cpu_load) {
866
double u, s;
867
u = get_cpu_load(-1, &_counters, &s, CPU_LOAD_VM_ONLY);
868
if (u < 0) {
869
*cpu_load = 0.0;
870
return OS_ERR;
871
}
872
*cpu_load = u + s;
873
return OS_OK;
874
}
875
876
int CPUPerformanceInterface::CPUPerformance::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) {
877
double u, s, t;
878
879
assert(pjvmUserLoad != NULL, "pjvmUserLoad not inited");
880
assert(pjvmKernelLoad != NULL, "pjvmKernelLoad not inited");
881
assert(psystemTotalLoad != NULL, "psystemTotalLoad not inited");
882
883
u = get_cpu_load(-1, &_counters, &s, CPU_LOAD_VM_ONLY);
884
if (u < 0) {
885
*pjvmUserLoad = 0.0;
886
*pjvmKernelLoad = 0.0;
887
*psystemTotalLoad = 0.0;
888
return OS_ERR;
889
}
890
891
cpu_load(-1, &t);
892
// clamp at user+system and 1.0
893
if (u + s > t) {
894
t = MIN2<double>(u + s, 1.0);
895
}
896
897
*pjvmUserLoad = u;
898
*pjvmKernelLoad = s;
899
*psystemTotalLoad = t;
900
901
return OS_OK;
902
}
903
904
int CPUPerformanceInterface::CPUPerformance::context_switch_rate(double* rate) {
905
return perf_context_switch_rate(rate);
906
}
907
908
CPUPerformanceInterface::CPUPerformanceInterface() {
909
_impl = NULL;
910
}
911
912
bool CPUPerformanceInterface::initialize() {
913
_impl = new CPUPerformanceInterface::CPUPerformance();
914
return _impl->initialize();
915
}
916
917
CPUPerformanceInterface::~CPUPerformanceInterface() {
918
if (_impl != NULL) {
919
delete _impl;
920
}
921
}
922
923
int CPUPerformanceInterface::cpu_load(int which_logical_cpu, double* cpu_load) const {
924
return _impl->cpu_load(which_logical_cpu, cpu_load);
925
}
926
927
int CPUPerformanceInterface::cpu_load_total_process(double* cpu_load) const {
928
return _impl->cpu_load_total_process(cpu_load);
929
}
930
931
int CPUPerformanceInterface::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) const {
932
return _impl->cpu_loads_process(pjvmUserLoad, pjvmKernelLoad, psystemTotalLoad);
933
}
934
935
int CPUPerformanceInterface::context_switch_rate(double* rate) const {
936
return _impl->context_switch_rate(rate);
937
}
938
939
class SystemProcessInterface::SystemProcesses : public CHeapObj<mtInternal> {
940
friend class SystemProcessInterface;
941
private:
942
class ProcessIterator : public CHeapObj<mtInternal> {
943
friend class SystemProcessInterface::SystemProcesses;
944
private:
945
DIR* _dir;
946
struct dirent* _entry;
947
bool _valid;
948
char _exeName[PATH_MAX];
949
char _exePath[PATH_MAX];
950
951
ProcessIterator();
952
~ProcessIterator();
953
bool initialize();
954
955
bool is_valid() const { return _valid; }
956
bool is_valid_entry(struct dirent* entry) const;
957
bool is_dir(const char* name) const;
958
int fsize(const char* name, uint64_t& size) const;
959
960
char* allocate_string(const char* str) const;
961
void get_exe_name();
962
char* get_exe_path();
963
char* get_cmdline();
964
965
int current(SystemProcess* process_info);
966
int next_process();
967
};
968
969
ProcessIterator* _iterator;
970
SystemProcesses();
971
bool initialize();
972
~SystemProcesses();
973
974
//information about system processes
975
int system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const;
976
};
977
978
bool SystemProcessInterface::SystemProcesses::ProcessIterator::is_dir(const char* name) const {
979
struct stat mystat;
980
int ret_val = 0;
981
982
ret_val = stat(name, &mystat);
983
if (ret_val < 0) {
984
return false;
985
}
986
ret_val = S_ISDIR(mystat.st_mode);
987
return ret_val > 0;
988
}
989
990
int SystemProcessInterface::SystemProcesses::ProcessIterator::fsize(const char* name, uint64_t& size) const {
991
assert(name != NULL, "name pointer is NULL!");
992
size = 0;
993
struct stat fbuf;
994
995
if (stat(name, &fbuf) < 0) {
996
return OS_ERR;
997
}
998
size = fbuf.st_size;
999
return OS_OK;
1000
}
1001
1002
// if it has a numeric name, is a directory and has a 'stat' file in it
1003
bool SystemProcessInterface::SystemProcesses::ProcessIterator::is_valid_entry(struct dirent* entry) const {
1004
char buffer[PATH_MAX];
1005
uint64_t size = 0;
1006
1007
if (atoi(entry->d_name) != 0) {
1008
jio_snprintf(buffer, PATH_MAX, "/proc/%s", entry->d_name);
1009
buffer[PATH_MAX - 1] = '\0';
1010
1011
if (is_dir(buffer)) {
1012
jio_snprintf(buffer, PATH_MAX, "/proc/%s/stat", entry->d_name);
1013
buffer[PATH_MAX - 1] = '\0';
1014
if (fsize(buffer, size) != OS_ERR) {
1015
return true;
1016
}
1017
}
1018
}
1019
return false;
1020
}
1021
1022
// get exe-name from /proc/<pid>/stat
1023
void SystemProcessInterface::SystemProcesses::ProcessIterator::get_exe_name() {
1024
FILE* fp;
1025
char buffer[PATH_MAX];
1026
1027
jio_snprintf(buffer, PATH_MAX, "/proc/%s/stat", _entry->d_name);
1028
buffer[PATH_MAX - 1] = '\0';
1029
if ((fp = fopen(buffer, "r")) != NULL) {
1030
if (fgets(buffer, PATH_MAX, fp) != NULL) {
1031
char* start, *end;
1032
// exe-name is between the first pair of ( and )
1033
start = strchr(buffer, '(');
1034
if (start != NULL && start[1] != '\0') {
1035
start++;
1036
end = strrchr(start, ')');
1037
if (end != NULL) {
1038
size_t len;
1039
len = MIN2<size_t>(end - start, sizeof(_exeName) - 1);
1040
memcpy(_exeName, start, len);
1041
_exeName[len] = '\0';
1042
}
1043
}
1044
}
1045
fclose(fp);
1046
}
1047
}
1048
1049
// get command line from /proc/<pid>/cmdline
1050
char* SystemProcessInterface::SystemProcesses::ProcessIterator::get_cmdline() {
1051
FILE* fp;
1052
char buffer[PATH_MAX];
1053
char* cmdline = NULL;
1054
1055
jio_snprintf(buffer, PATH_MAX, "/proc/%s/cmdline", _entry->d_name);
1056
buffer[PATH_MAX - 1] = '\0';
1057
if ((fp = fopen(buffer, "r")) != NULL) {
1058
size_t size = 0;
1059
char dummy;
1060
1061
// find out how long the file is (stat always returns 0)
1062
while (fread(&dummy, 1, 1, fp) == 1) {
1063
size++;
1064
}
1065
if (size > 0) {
1066
cmdline = NEW_C_HEAP_ARRAY(char, size + 1, mtInternal);
1067
cmdline[0] = '\0';
1068
if (fseek(fp, 0, SEEK_SET) == 0) {
1069
if (fread(cmdline, 1, size, fp) == size) {
1070
// the file has the arguments separated by '\0',
1071
// so we translate '\0' to ' '
1072
for (size_t i = 0; i < size; i++) {
1073
if (cmdline[i] == '\0') {
1074
cmdline[i] = ' ';
1075
}
1076
}
1077
cmdline[size] = '\0';
1078
}
1079
}
1080
}
1081
fclose(fp);
1082
}
1083
return cmdline;
1084
}
1085
1086
// get full path to exe from /proc/<pid>/exe symlink
1087
char* SystemProcessInterface::SystemProcesses::ProcessIterator::get_exe_path() {
1088
char buffer[PATH_MAX];
1089
1090
jio_snprintf(buffer, PATH_MAX, "/proc/%s/exe", _entry->d_name);
1091
buffer[PATH_MAX - 1] = '\0';
1092
return realpath(buffer, _exePath);
1093
}
1094
1095
char* SystemProcessInterface::SystemProcesses::ProcessIterator::allocate_string(const char* str) const {
1096
if (str != NULL) {
1097
return os::strdup_check_oom(str, mtInternal);
1098
}
1099
return NULL;
1100
}
1101
1102
int SystemProcessInterface::SystemProcesses::ProcessIterator::current(SystemProcess* process_info) {
1103
if (!is_valid()) {
1104
return OS_ERR;
1105
}
1106
1107
process_info->set_pid(atoi(_entry->d_name));
1108
1109
get_exe_name();
1110
process_info->set_name(allocate_string(_exeName));
1111
1112
if (get_exe_path() != NULL) {
1113
process_info->set_path(allocate_string(_exePath));
1114
}
1115
1116
char* cmdline = NULL;
1117
cmdline = get_cmdline();
1118
if (cmdline != NULL) {
1119
process_info->set_command_line(allocate_string(cmdline));
1120
FREE_C_HEAP_ARRAY(char, cmdline);
1121
}
1122
1123
return OS_OK;
1124
}
1125
1126
int SystemProcessInterface::SystemProcesses::ProcessIterator::next_process() {
1127
if (!is_valid()) {
1128
return OS_ERR;
1129
}
1130
1131
do {
1132
_entry = os::readdir(_dir);
1133
if (_entry == NULL) {
1134
// Error or reached end. Could use errno to distinguish those cases.
1135
_valid = false;
1136
return OS_ERR;
1137
}
1138
} while(!is_valid_entry(_entry));
1139
1140
_valid = true;
1141
return OS_OK;
1142
}
1143
1144
SystemProcessInterface::SystemProcesses::ProcessIterator::ProcessIterator() {
1145
_dir = NULL;
1146
_entry = NULL;
1147
_valid = false;
1148
}
1149
1150
bool SystemProcessInterface::SystemProcesses::ProcessIterator::initialize() {
1151
_dir = os::opendir("/proc");
1152
_entry = NULL;
1153
_valid = true;
1154
next_process();
1155
1156
return true;
1157
}
1158
1159
SystemProcessInterface::SystemProcesses::ProcessIterator::~ProcessIterator() {
1160
if (_dir != NULL) {
1161
os::closedir(_dir);
1162
}
1163
}
1164
1165
SystemProcessInterface::SystemProcesses::SystemProcesses() {
1166
_iterator = NULL;
1167
}
1168
1169
bool SystemProcessInterface::SystemProcesses::initialize() {
1170
_iterator = new SystemProcessInterface::SystemProcesses::ProcessIterator();
1171
return _iterator->initialize();
1172
}
1173
1174
SystemProcessInterface::SystemProcesses::~SystemProcesses() {
1175
if (_iterator != NULL) {
1176
delete _iterator;
1177
}
1178
}
1179
1180
int SystemProcessInterface::SystemProcesses::system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const {
1181
assert(system_processes != NULL, "system_processes pointer is NULL!");
1182
assert(no_of_sys_processes != NULL, "system_processes counter pointers is NULL!");
1183
assert(_iterator != NULL, "iterator is NULL!");
1184
1185
// initialize pointers
1186
*no_of_sys_processes = 0;
1187
*system_processes = NULL;
1188
1189
while (_iterator->is_valid()) {
1190
SystemProcess* tmp = new SystemProcess();
1191
_iterator->current(tmp);
1192
1193
//if already existing head
1194
if (*system_processes != NULL) {
1195
//move "first to second"
1196
tmp->set_next(*system_processes);
1197
}
1198
// new head
1199
*system_processes = tmp;
1200
// increment
1201
(*no_of_sys_processes)++;
1202
// step forward
1203
_iterator->next_process();
1204
}
1205
return OS_OK;
1206
}
1207
1208
int SystemProcessInterface::system_processes(SystemProcess** system_procs, int* no_of_sys_processes) const {
1209
return _impl->system_processes(system_procs, no_of_sys_processes);
1210
}
1211
1212
SystemProcessInterface::SystemProcessInterface() {
1213
_impl = NULL;
1214
}
1215
1216
bool SystemProcessInterface::initialize() {
1217
_impl = new SystemProcessInterface::SystemProcesses();
1218
return _impl->initialize();
1219
}
1220
1221
SystemProcessInterface::~SystemProcessInterface() {
1222
if (_impl != NULL) {
1223
delete _impl;
1224
}
1225
}
1226
1227
CPUInformationInterface::CPUInformationInterface() {
1228
_cpu_info = NULL;
1229
}
1230
1231
bool CPUInformationInterface::initialize() {
1232
_cpu_info = new CPUInformation();
1233
_cpu_info->set_number_of_hardware_threads(VM_Version_Ext::number_of_threads());
1234
_cpu_info->set_number_of_cores(VM_Version_Ext::number_of_cores());
1235
_cpu_info->set_number_of_sockets(VM_Version_Ext::number_of_sockets());
1236
_cpu_info->set_cpu_name(VM_Version_Ext::cpu_name());
1237
_cpu_info->set_cpu_description(VM_Version_Ext::cpu_description());
1238
return true;
1239
}
1240
1241
CPUInformationInterface::~CPUInformationInterface() {
1242
if (_cpu_info != NULL) {
1243
if (_cpu_info->cpu_name() != NULL) {
1244
const char* cpu_name = _cpu_info->cpu_name();
1245
FREE_C_HEAP_ARRAY(char, cpu_name);
1246
_cpu_info->set_cpu_name(NULL);
1247
}
1248
if (_cpu_info->cpu_description() != NULL) {
1249
const char* cpu_desc = _cpu_info->cpu_description();
1250
FREE_C_HEAP_ARRAY(char, cpu_desc);
1251
_cpu_info->set_cpu_description(NULL);
1252
}
1253
delete _cpu_info;
1254
}
1255
}
1256
1257
int CPUInformationInterface::cpu_information(CPUInformation& cpu_info) {
1258
if (_cpu_info == NULL) {
1259
return OS_ERR;
1260
}
1261
1262
cpu_info = *_cpu_info; // shallow copy assignment
1263
return OS_OK;
1264
}
1265
1266
class NetworkPerformanceInterface::NetworkPerformance : public CHeapObj<mtInternal> {
1267
friend class NetworkPerformanceInterface;
1268
private:
1269
NetworkPerformance();
1270
NONCOPYABLE(NetworkPerformance);
1271
bool initialize();
1272
~NetworkPerformance();
1273
int64_t read_counter(const char* iface, const char* counter) const;
1274
int network_utilization(NetworkInterface** network_interfaces) const;
1275
};
1276
1277
NetworkPerformanceInterface::NetworkPerformance::NetworkPerformance() {
1278
1279
}
1280
1281
bool NetworkPerformanceInterface::NetworkPerformance::initialize() {
1282
return true;
1283
}
1284
1285
NetworkPerformanceInterface::NetworkPerformance::~NetworkPerformance() {
1286
}
1287
1288
int64_t NetworkPerformanceInterface::NetworkPerformance::read_counter(const char* iface, const char* counter) const {
1289
char buf[128];
1290
1291
snprintf(buf, sizeof(buf), "/sys/class/net/%s/statistics/%s", iface, counter);
1292
1293
int fd = os::open(buf, O_RDONLY, 0);
1294
if (fd == -1) {
1295
return -1;
1296
}
1297
1298
ssize_t num_bytes = read(fd, buf, sizeof(buf));
1299
close(fd);
1300
if ((num_bytes == -1) || (num_bytes >= static_cast<ssize_t>(sizeof(buf))) || (num_bytes < 1)) {
1301
return -1;
1302
}
1303
1304
buf[num_bytes] = '\0';
1305
int64_t value = strtoll(buf, NULL, 10);
1306
1307
return value;
1308
}
1309
1310
int NetworkPerformanceInterface::NetworkPerformance::network_utilization(NetworkInterface** network_interfaces) const
1311
{
1312
ifaddrs* addresses;
1313
ifaddrs* cur_address;
1314
1315
if (getifaddrs(&addresses) != 0) {
1316
return OS_ERR;
1317
}
1318
1319
NetworkInterface* ret = NULL;
1320
for (cur_address = addresses; cur_address != NULL; cur_address = cur_address->ifa_next) {
1321
if ((cur_address->ifa_addr == NULL) || (cur_address->ifa_addr->sa_family != AF_PACKET)) {
1322
continue;
1323
}
1324
1325
int64_t bytes_in = read_counter(cur_address->ifa_name, "rx_bytes");
1326
int64_t bytes_out = read_counter(cur_address->ifa_name, "tx_bytes");
1327
1328
NetworkInterface* cur = new NetworkInterface(cur_address->ifa_name, bytes_in, bytes_out, ret);
1329
ret = cur;
1330
}
1331
1332
freeifaddrs(addresses);
1333
*network_interfaces = ret;
1334
1335
return OS_OK;
1336
}
1337
1338
NetworkPerformanceInterface::NetworkPerformanceInterface() {
1339
_impl = NULL;
1340
}
1341
1342
NetworkPerformanceInterface::~NetworkPerformanceInterface() {
1343
if (_impl != NULL) {
1344
delete _impl;
1345
}
1346
}
1347
1348
bool NetworkPerformanceInterface::initialize() {
1349
_impl = new NetworkPerformanceInterface::NetworkPerformance();
1350
return _impl->initialize();
1351
}
1352
1353
int NetworkPerformanceInterface::network_utilization(NetworkInterface** network_interfaces) const {
1354
return _impl->network_utilization(network_interfaces);
1355
}
1356
1357