jdk

Форк
0
/
os_perf_aix.cpp 
627 строк · 18.1 Кб
1
/*
2
 * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved.
3
 * Copyright (c) 2022, 2024, IBM Corp.
4
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5
 *
6
 * This code is free software; you can redistribute it and/or modify it
7
 * under the terms of the GNU General Public License version 2 only, as
8
 * published by the Free Software Foundation.
9
 *
10
 * This code is distributed in the hope that it will be useful, but WITHOUT
11
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13
 * version 2 for more details (a copy is included in the LICENSE file that
14
 * accompanied this code).
15
 *
16
 * You should have received a copy of the GNU General Public License version
17
 * 2 along with this work; if not, write to the Free Software Foundation,
18
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19
 *
20
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21
 * or visit www.oracle.com if you need additional information or have any
22
 * questions.
23
 *
24
 */
25

26
#include "precompiled.hpp"
27
#include "jvm.h"
28
#include "libperfstat_aix.hpp"
29
#include "memory/allocation.inline.hpp"
30
#include "memory/resourceArea.hpp"
31
#include "os_aix.inline.hpp"
32
#include "runtime/os.hpp"
33
#include "runtime/os_perf.hpp"
34
#include "runtime/vm_version.hpp"
35
#include "utilities/debug.hpp"
36
#include "utilities/globalDefinitions.hpp"
37

38
#include <dirent.h>
39
#include <dlfcn.h>
40
#include <errno.h>
41
#include <limits.h>
42
#include <pthread.h>
43
#include <stdarg.h>
44
#include <stdio.h>
45
#include <string.h>
46
#include <sys/procfs.h>
47
#include <sys/resource.h>
48
#include <sys/stat.h>
49
#include <sys/types.h>
50
#include <stdlib.h>
51
#include <unistd.h>
52

53
typedef struct {
54
  u_longlong_t  user;
55
  u_longlong_t  sys;
56
  u_longlong_t  idle;
57
  u_longlong_t  wait;
58
} cpu_tick_store_t;
59

60
typedef struct {
61
  double utime;
62
  double stime;
63
} jvm_time_store_t;
64

65
enum {
66
  UNDETECTED,
67
  UNDETECTABLE,
68
  LINUX26_NPTL,
69
  BAREMETAL
70
};
71

72
/**
73
 * Get info for requested PID from /proc/<pid>/psinfo file
74
 */
75
static bool read_psinfo(const u_longlong_t& pid, psinfo_t& psinfo) {
76
  static size_t BUF_LENGTH = 32 + sizeof(u_longlong_t);
77

78
  FILE* fp;
79
  char buf[BUF_LENGTH];
80
  size_t len;
81

82
  jio_snprintf(buf, BUF_LENGTH, "/proc/%llu/psinfo", pid);
83
  fp = fopen(buf, "r");
84

85
  if (!fp) {
86
    return false;
87
  }
88

89
  len = fread(&psinfo, 1, sizeof(psinfo_t), fp);
90
  fclose(fp);
91
  return len == sizeof(psinfo_t);
92
}
93

94
/**
95
 * Get and set ticks for the specified lcpu
96
 */
97
static OSReturn get_lcpu_ticks(perfstat_id_t* lcpu_name, cpu_tick_store_t* pticks) {
98
  perfstat_cpu_t lcpu_stats;
99

100
  if (!pticks) {
101
    return OS_ERR;
102
  }
103

104
  // populate cpu_stats
105
  if (libperfstat::perfstat_cpu(lcpu_name, &lcpu_stats, sizeof(perfstat_cpu_t), 1) < 1) {
106
    memset(pticks, 0, sizeof(cpu_tick_store_t));
107
    return OS_ERR;
108
  }
109

110
  pticks->user = lcpu_stats.user;
111
  pticks->sys  = lcpu_stats.sys;
112
  pticks->idle = lcpu_stats.idle;
113
  pticks->wait = lcpu_stats.wait;
114

115
  return OS_OK;
116
}
117

118
/**
119
 * Return CPU load caused by the currently executing process (the jvm).
120
 */
121
static OSReturn get_jvm_load(double* jvm_uload, double* jvm_sload) {
122
  static clock_t ticks_per_sec = sysconf(_SC_CLK_TCK);
123
  static u_longlong_t last_timebase = 0;
124

125
  perfstat_process_t jvm_stats;
126
  perfstat_id_t name_holder;
127
  u_longlong_t timebase_diff;
128

129
  jio_snprintf(name_holder.name, IDENTIFIER_LENGTH, "%d", getpid());
130
  if (libperfstat::perfstat_process(&name_holder, &jvm_stats, sizeof(perfstat_process_t), 1) < 1) {
131
    return OS_ERR;
132
  }
133

134
  // Update timebase
135
  timebase_diff = jvm_stats.last_timebase - last_timebase;
136
  last_timebase = jvm_stats.last_timebase;
137

138
  if (jvm_uload) {
139
    *jvm_uload = jvm_stats.ucpu_time / timebase_diff;
140
  }
141
  if (jvm_sload) {
142
    *jvm_sload = jvm_stats.scpu_time / timebase_diff;
143
  }
144

145
  return OS_OK;
146
}
147

148
static void update_prev_time(jvm_time_store_t* from, jvm_time_store_t* to) {
149
  if (from && to) {
150
    memcpy(to, from, sizeof(jvm_time_store_t));
151
  }
152
}
153

154
static void update_prev_ticks(cpu_tick_store_t* from, cpu_tick_store_t* to) {
155
  if (from && to) {
156
    memcpy(to, from, sizeof(cpu_tick_store_t));
157
  }
158
}
159

160
/**
161
 * Calculate the current system load from current ticks using previous ticks as a starting point.
162
 */
163
static void calculate_updated_load(cpu_tick_store_t* update, cpu_tick_store_t* prev, double* load) {
164
  cpu_tick_store_t diff;
165

166
  if (update && prev && load) {
167
    diff.user = update->user - prev->user;
168
    diff.sys  = update->sys  - prev->sys;
169
    diff.idle = update->idle - prev->idle;
170
    diff.wait = update->wait - prev->wait;
171

172
    *load = 1.0 - diff.idle/(diff.sys + diff.user + diff.idle + diff.wait);
173
  }
174
}
175

176
/**
177
 * Look up lcpu names for later re-use.
178
 */
179
static bool populate_lcpu_names(int ncpus, perfstat_id_t* lcpu_names) {
180
  ResourceMark rm;
181
  perfstat_cpu_t* all_lcpu_stats;
182
  perfstat_cpu_t* lcpu_stats;
183
  perfstat_id_t   name_holder;
184

185
  assert(lcpu_names, "Names pointer null");
186

187
  strncpy(name_holder.name, FIRST_CPU, IDENTIFIER_LENGTH);
188

189
  all_lcpu_stats = NEW_RESOURCE_ARRAY(perfstat_cpu_t, ncpus);
190

191
  // If perfstat_cpu does not return the expected number of names, signal error to caller
192
  if (ncpus != libperfstat::perfstat_cpu(&name_holder, all_lcpu_stats, sizeof(perfstat_cpu_t), ncpus)) {
193
    return false;
194
  }
195

196
  for (int n = 0; n < ncpus; n++) {
197
    strncpy(lcpu_names[n].name, all_lcpu_stats[n].name, IDENTIFIER_LENGTH);
198
  }
199

200
  return true;
201
}
202

203
/**
204
 * Calculates the context switch rate.
205
 * (Context Switches / Tick) * (Tick / s) = Context Switches per second
206
 */
207
static OSReturn perf_context_switch_rate(double* rate) {
208
  static clock_t ticks_per_sec = sysconf(_SC_CLK_TCK);
209

210
  u_longlong_t ticks;
211
  perfstat_cpu_total_t cpu_stats;
212

213
   if (libperfstat::perfstat_cpu_total(nullptr, &cpu_stats, sizeof(perfstat_cpu_total_t), 1) < 0) {
214
     return OS_ERR;
215
   }
216

217
   ticks = cpu_stats.user + cpu_stats.sys + cpu_stats.idle + cpu_stats.wait;
218
   *rate = (cpu_stats.pswitch / ticks) * ticks_per_sec;
219

220
   return OS_OK;
221
}
222

223
class CPUPerformanceInterface::CPUPerformance : public CHeapObj<mtInternal> {
224
 private:
225
  int _ncpus;
226
  perfstat_id_t* _lcpu_names;
227
  cpu_tick_store_t* _prev_ticks;
228

229
 public:
230
  CPUPerformance();
231
  bool initialize();
232
  ~CPUPerformance();
233

234
  int cpu_load(int which_logical_cpu, double* cpu_load);
235
  int context_switch_rate(double* rate);
236
  int cpu_load_total_process(double* cpu_load);
237
  int cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad);
238
};
239

240
CPUPerformanceInterface::CPUPerformance::CPUPerformance():
241
  _ncpus(0),
242
  _lcpu_names(nullptr),
243
  _prev_ticks(nullptr) {}
244

245
bool CPUPerformanceInterface::CPUPerformance::initialize() {
246
  perfstat_cpu_total_t cpu_stats;
247

248
  if (libperfstat::perfstat_cpu_total(nullptr, &cpu_stats, sizeof(perfstat_cpu_total_t), 1) < 0) {
249
    return false;
250
  }
251
  if (cpu_stats.ncpus <= 0) {
252
    return false;
253
  }
254

255
  _ncpus = cpu_stats.ncpus;
256
  _lcpu_names = NEW_C_HEAP_ARRAY(perfstat_id_t, _ncpus, mtInternal);
257

258
  _prev_ticks = NEW_C_HEAP_ARRAY(cpu_tick_store_t, _ncpus, mtInternal);
259
  // Set all prev-tick values to 0
260
  memset(_prev_ticks, 0, _ncpus*sizeof(cpu_tick_store_t));
261

262
  if (!populate_lcpu_names(_ncpus, _lcpu_names)) {
263
    return false;
264
  }
265

266
  return true;
267
}
268

269
CPUPerformanceInterface::CPUPerformance::~CPUPerformance() {
270
  if (_lcpu_names) {
271
    FREE_C_HEAP_ARRAY(perfstat_id_t, _lcpu_names);
272
  }
273
  if (_prev_ticks) {
274
    FREE_C_HEAP_ARRAY(cpu_tick_store_t, _prev_ticks);
275
  }
276
}
277

278
/**
279
 * Get CPU load for all processes on specified logical CPU.
280
 */
281
int CPUPerformanceInterface::CPUPerformance::cpu_load(int lcpu_number, double* lcpu_load) {
282
  cpu_tick_store_t ticks;
283

284
  assert(lcpu_load != nullptr, "null pointer passed to cpu_load");
285
  assert(lcpu_number < _ncpus, "Invalid lcpu passed to cpu_load");
286

287
  if (get_lcpu_ticks(&_lcpu_names[lcpu_number], &ticks) == OS_ERR) {
288
    *lcpu_load = -1.0;
289
    return OS_ERR;
290
  }
291

292
  calculate_updated_load(&ticks, &_prev_ticks[lcpu_number], lcpu_load);
293
  update_prev_ticks(&ticks, &_prev_ticks[lcpu_number]);
294

295
  return OS_OK;
296
}
297

298
/**
299
 * Get CPU load for all processes on all CPUs.
300
 */
301
int CPUPerformanceInterface::CPUPerformance::cpu_load_total_process(double* total_load) {
302
  cpu_tick_store_t total_ticks;
303
  cpu_tick_store_t prev_total_ticks;
304

305
  assert(total_load != nullptr, "null pointer passed to cpu_load_total_process");
306

307
  memset(&total_ticks, 0, sizeof(cpu_tick_store_t));
308
  memset(&prev_total_ticks, 0, sizeof(cpu_tick_store_t));
309

310
  for (int lcpu = 0; lcpu < _ncpus; lcpu++) {
311
    cpu_tick_store_t lcpu_ticks;
312

313
    if (get_lcpu_ticks(&_lcpu_names[lcpu], &lcpu_ticks) == OS_ERR) {
314
      *total_load = -1.0;
315
      return OS_ERR;
316
    }
317

318
    total_ticks.user = lcpu_ticks.user;
319
    total_ticks.sys  = lcpu_ticks.sys;
320
    total_ticks.idle = lcpu_ticks.idle;
321
    total_ticks.wait = lcpu_ticks.wait;
322

323
    prev_total_ticks.user += _prev_ticks[lcpu].user;
324
    prev_total_ticks.sys  += _prev_ticks[lcpu].sys;
325
    prev_total_ticks.idle += _prev_ticks[lcpu].idle;
326
    prev_total_ticks.wait += _prev_ticks[lcpu].wait;
327

328
    update_prev_ticks(&lcpu_ticks, &_prev_ticks[lcpu]);
329
  }
330

331
  calculate_updated_load(&total_ticks, &prev_total_ticks, total_load);
332

333
  return OS_OK;
334
}
335

336
/**
337
 * Get CPU load for all CPUs.
338
 *
339
 * Set values for:
340
 * - pjvmUserLoad:     CPU load due to jvm process in user mode. Jvm process assumed to be self process
341
 * - pjvmKernelLoad:   CPU load due to jvm process in kernel mode. Jvm process assumed to be self process
342
 * - psystemTotalLoad: Total CPU load from all process on all logical CPUs
343
 *
344
 * Note: If any of the above loads cannot be calculated, this procedure returns OS_ERR and any load that could not be calculated is set to -1
345
 *
346
 */
347
int CPUPerformanceInterface::CPUPerformance::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) {
348
  double u, k, t;
349

350
  int retval = OS_OK;
351
  if (get_jvm_load(&u, &k) == OS_ERR || cpu_load_total_process(&t) == OS_ERR) {
352
    retval = OS_ERR;
353
  }
354

355
  if (pjvmUserLoad) {
356
    *pjvmUserLoad = u;
357
  }
358
  if (pjvmKernelLoad) {
359
    *pjvmKernelLoad = k;
360
  }
361
  if (psystemTotalLoad) {
362
    *psystemTotalLoad = t;
363
  }
364

365
  return retval;
366
}
367

368
int CPUPerformanceInterface::CPUPerformance::context_switch_rate(double* rate) {
369
  return perf_context_switch_rate(rate);
370
}
371

372
CPUPerformanceInterface::CPUPerformanceInterface() {
373
  _impl = nullptr;
374
}
375

376
bool CPUPerformanceInterface::initialize() {
377
  _impl = new CPUPerformanceInterface::CPUPerformance();
378
  return _impl->initialize();
379
}
380

381
CPUPerformanceInterface::~CPUPerformanceInterface() {
382
  if (_impl != nullptr) {
383
    delete _impl;
384
  }
385
}
386

387
int CPUPerformanceInterface::cpu_load(int which_logical_cpu, double* cpu_load) const {
388
  return _impl->cpu_load(which_logical_cpu, cpu_load);
389
}
390

391
int CPUPerformanceInterface::cpu_load_total_process(double* cpu_load) const {
392
  return _impl->cpu_load_total_process(cpu_load);
393
}
394

395
int CPUPerformanceInterface::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) const {
396
  return _impl->cpu_loads_process(pjvmUserLoad, pjvmKernelLoad, psystemTotalLoad);
397
}
398

399
int CPUPerformanceInterface::context_switch_rate(double* rate) const {
400
  return _impl->context_switch_rate(rate);
401
}
402

403
class SystemProcessInterface::SystemProcesses : public CHeapObj<mtInternal> {
404
  private:
405
  char* allocate_string(const char* str) const;
406

407
  public:
408
  SystemProcesses();
409
  bool initialize();
410
  ~SystemProcesses();
411
  int system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const;
412
};
413

414
SystemProcessInterface::SystemProcesses::SystemProcesses() {
415
}
416

417
bool SystemProcessInterface::SystemProcesses::initialize() {
418
  return true;
419
}
420

421
SystemProcessInterface::SystemProcesses::~SystemProcesses() {
422
}
423

424
char* SystemProcessInterface::SystemProcesses::allocate_string(const char* str) const {
425
  if (str != nullptr) {
426
    return os::strdup_check_oom(str, mtInternal);
427
  }
428
  return nullptr;
429
}
430

431
int SystemProcessInterface::SystemProcesses::system_processes(SystemProcess** system_processes, int* nprocs) const {
432
  ResourceMark rm;
433
  perfstat_process_t* proc_stats;
434
  SystemProcess* head;
435
  perfstat_id_t name_holder;
436
  int records_allocated = 0;
437

438
  assert(nprocs != nullptr, "system_processes counter pointers is null!");
439

440
  head = nullptr;
441
  *nprocs = 0;
442
  strncpy(name_holder.name, "", IDENTIFIER_LENGTH);
443

444
  // calling perfstat_<subsystem>(null, null, _, 0) returns number of available records
445
  *nprocs = libperfstat::perfstat_process(nullptr, nullptr, sizeof(perfstat_process_t), 0);
446
  if(*nprocs < 1) {
447
    // expect at least 1 process
448
    return OS_ERR;
449
  }
450

451
  records_allocated = *nprocs;
452
  proc_stats = NEW_RESOURCE_ARRAY(perfstat_process_t, records_allocated);
453

454
  // populate stats && set the actual number of procs that have been populated
455
  // should never be higher than requested, but may be lower due to process death
456
  *nprocs = libperfstat::perfstat_process(&name_holder, proc_stats, sizeof(perfstat_process_t), records_allocated);
457

458
  for (int n = 0; n < *nprocs; n++) {
459
    psinfo_t psinfo;
460
    // Note: SystemProcess with free these in its dtor.
461
    char* name     = NEW_C_HEAP_ARRAY(char, IDENTIFIER_LENGTH, mtInternal);
462
    char* exe_name = NEW_C_HEAP_ARRAY(char, PRFNSZ, mtInternal);
463
    char* cmd_line = NEW_C_HEAP_ARRAY(char, PRARGSZ, mtInternal);
464

465
    strncpy(name, proc_stats[n].proc_name, IDENTIFIER_LENGTH);
466

467
    if (read_psinfo(proc_stats[n].pid, psinfo)) {
468
      strncpy(exe_name, psinfo.pr_fname, PRFNSZ);
469
      strncpy(cmd_line, psinfo.pr_psargs, PRARGSZ);
470
    }
471

472
    // create a new SystemProcess with next pointing to current head.
473
    SystemProcess* sp = new SystemProcess(proc_stats[n].pid,
474
                                          name,
475
                                          exe_name,
476
                                          cmd_line,
477
                                          head);
478
    // update head.
479
    head = sp;
480
  }
481

482
  *system_processes = head;
483
  return OS_OK;
484
}
485

486
int SystemProcessInterface::system_processes(SystemProcess** system_procs, int* no_of_sys_processes) const {
487
  return _impl->system_processes(system_procs, no_of_sys_processes);
488
}
489

490
SystemProcessInterface::SystemProcessInterface() {
491
  _impl = nullptr;
492
}
493

494
bool SystemProcessInterface::initialize() {
495
  _impl = new SystemProcessInterface::SystemProcesses();
496
  return _impl->initialize();
497
}
498

499
SystemProcessInterface::~SystemProcessInterface() {
500
  if (_impl != nullptr) {
501
    delete _impl;
502
  }
503
}
504

505
CPUInformationInterface::CPUInformationInterface() {
506
  _cpu_info = nullptr;
507
}
508

509
bool CPUInformationInterface::initialize() {
510
  _cpu_info = new CPUInformation();
511
  VM_Version::initialize_cpu_information();
512
  _cpu_info->set_number_of_hardware_threads(VM_Version::number_of_threads());
513
  _cpu_info->set_number_of_cores(VM_Version::number_of_cores());
514
  _cpu_info->set_number_of_sockets(VM_Version::number_of_sockets());
515
  _cpu_info->set_cpu_name(VM_Version::cpu_name());
516
  _cpu_info->set_cpu_description(VM_Version::cpu_description());
517
  return true;
518
}
519

520
CPUInformationInterface::~CPUInformationInterface() {
521
  if (_cpu_info != nullptr) {
522
    if (_cpu_info->cpu_name() != nullptr) {
523
      const char* cpu_name = _cpu_info->cpu_name();
524
      FREE_C_HEAP_ARRAY(char, cpu_name);
525
      _cpu_info->set_cpu_name(nullptr);
526
    }
527
    if (_cpu_info->cpu_description() != nullptr) {
528
       const char* cpu_desc = _cpu_info->cpu_description();
529
       FREE_C_HEAP_ARRAY(char, cpu_desc);
530
      _cpu_info->set_cpu_description(nullptr);
531
    }
532
    delete _cpu_info;
533
  }
534
}
535

536
int CPUInformationInterface::cpu_information(CPUInformation& cpu_info) {
537
  if (_cpu_info == nullptr) {
538
    return OS_ERR;
539
  }
540

541
  cpu_info = *_cpu_info; // shallow copy assignment
542
  return OS_OK;
543
}
544

545
class NetworkPerformanceInterface::NetworkPerformance : public CHeapObj<mtInternal> {
546
  NONCOPYABLE(NetworkPerformance);
547

548
 private:
549
  char* allocate_string(const char* str) const;
550

551
  public:
552
  NetworkPerformance();
553
  bool initialize();
554
  ~NetworkPerformance();
555
  int network_utilization(NetworkInterface** network_interfaces) const;
556
};
557

558
NetworkPerformanceInterface::NetworkPerformance::NetworkPerformance() {}
559

560
bool NetworkPerformanceInterface::NetworkPerformance::initialize() {
561
  return true;
562
}
563

564
NetworkPerformanceInterface::NetworkPerformance::~NetworkPerformance() {}
565

566
int NetworkPerformanceInterface::NetworkPerformance::network_utilization(NetworkInterface** network_interfaces) const {
567
  int n_records = 0;
568
  perfstat_netinterface_t* net_stats;
569
  perfstat_id_t name_holder;
570
  int records_allocated = 0;
571

572
  assert(network_interfaces != nullptr, "network_interfaces is null");
573

574
  *network_interfaces = nullptr;
575
  strncpy(name_holder.name , FIRST_NETINTERFACE, IDENTIFIER_LENGTH);
576

577
  // calling perfstat_<subsystem>(null, null, _, 0) returns number of available records
578
  if ((n_records = libperfstat::perfstat_netinterface(nullptr, nullptr, sizeof(perfstat_netinterface_t), 0)) < 0) {
579
    return OS_ERR;
580
  }
581

582
  records_allocated = n_records;
583
  net_stats = NEW_C_HEAP_ARRAY(perfstat_netinterface_t, records_allocated, mtInternal);
584

585
  n_records = libperfstat::perfstat_netinterface(&name_holder, net_stats, sizeof(perfstat_netinterface_t), n_records);
586

587
  // check for error
588
  if (n_records < 0) {
589
    FREE_C_HEAP_ARRAY(perfstat_netinterface_t, net_stats);
590
    return OS_ERR;
591
  }
592

593
  for (int i = 0; i < n_records; i++) {
594
    // Create new Network interface *with current head as next node*
595
    // Note: NetworkInterface makes copies of these string values into RA memory
596
    // this means:
597
    // (1) we are free to clean our values upon exiting this proc
598
    // (2) we avoid using RA-alloced memory here (ie. do not use NEW_RESOURCE_ARRAY)
599
    NetworkInterface* new_interface = new NetworkInterface(net_stats[i].name,
600
                                                           net_stats[i].ibytes,
601
                                                           net_stats[i].obytes,
602
                                                           *network_interfaces);
603
    *network_interfaces = new_interface;
604
  }
605

606
  FREE_C_HEAP_ARRAY(perfstat_netinterface_t, net_stats);
607
  return OS_OK;
608
}
609

610
NetworkPerformanceInterface::NetworkPerformanceInterface() {
611
  _impl = nullptr;
612
}
613

614
NetworkPerformanceInterface::~NetworkPerformanceInterface() {
615
  if (_impl != nullptr) {
616
    delete _impl;
617
  }
618
}
619

620
bool NetworkPerformanceInterface::initialize() {
621
  _impl = new NetworkPerformanceInterface::NetworkPerformance();
622
  return _impl->initialize();
623
}
624

625
int NetworkPerformanceInterface::network_utilization(NetworkInterface** network_interfaces) const {
626
  return _impl->network_utilization(network_interfaces);
627
}
628

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.