text: /*
   * Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
   * Use of this source code is governed by a BSD-style license that can be
   * found in the LICENSE file.
   *
   * Functions related to the Windows Management Instrumentation API.
   */
  
  #include <Python.h>
  #include <windows.h>
  #include <pdh.h>
  
  
  // We use an exponentially weighted moving average, just like Unix systems do
  // https://en.wikipedia.org/wiki/Load_(computing)#Unix-style_load_calculation
  //
  // These constants serve as the damping factor and are calculated with
  // 1 / exp(sampling interval in seconds / window size in seconds)
  //
  // This formula comes from linux's include/linux/sched/loadavg.h
  // https://github.com/torvalds/linux/blob/345671ea0f9258f410eb057b9ced9cefbbe5dc78/include/linux/sched/loadavg.h#L20-L23
  #define LOADAVG_FACTOR_1F  0.9200444146293232478931553241
  #define LOADAVG_FACTOR_5F  0.9834714538216174894737477501
  #define LOADAVG_FACTOR_15F 0.9944598480048967508795473394
  // The time interval in seconds between taking load counts, same as Linux
  #define SAMPLING_INTERVAL 5
  
  double load_avg_1m = 0;
  double load_avg_5m = 0;
  double load_avg_15m = 0;
  
  
  VOID CALLBACK LoadAvgCallback(PVOID hCounter) {
      PDH_FMT_COUNTERVALUE displayValue;
      double currentLoad;
      PDH_STATUS err;
  
      err = PdhGetFormattedCounterValue(
          (PDH_HCOUNTER)hCounter, PDH_FMT_DOUBLE, 0, &displayValue);
      // Skip updating the load if we can't get the value successfully
      if (err != ERROR_SUCCESS) {
          return;
      }
      currentLoad = displayValue.doubleValue;
  
      load_avg_1m = load_avg_1m * LOADAVG_FACTOR_1F + currentLoad * \
          (1.0 - LOADAVG_FACTOR_1F);
      load_avg_5m = load_avg_5m * LOADAVG_FACTOR_5F + currentLoad * \
          (1.0 - LOADAVG_FACTOR_5F);
      load_avg_15m = load_avg_15m * LOADAVG_FACTOR_15F + currentLoad * \
          (1.0 - LOADAVG_FACTOR_15F);
  }
  
  
  PyObject *
  psutil_init_loadavg_counter(PyObject *self, PyObject *args) {
      WCHAR *szCounterPath = L"\\System\\Processor Queue Length";
      PDH_STATUS s;
      BOOL ret;
      HQUERY hQuery;
      HCOUNTER hCounter;
      HANDLE event;
      HANDLE waitHandle;
  
      if ((PdhOpenQueryW(NULL, 0, &hQuery)) != ERROR_SUCCESS)
          goto error;
  
      s = PdhAddEnglishCounterW(hQuery, szCounterPath, 0, &hCounter);
      if (s != ERROR_SUCCESS)
          goto error;
  
      event = CreateEventW(NULL, FALSE, FALSE, L"LoadUpdateEvent");
      if (event == NULL) {
          PyErr_SetFromWindowsErr(GetLastError());
          return NULL;
      }
  
      s = PdhCollectQueryDataEx(hQuery, SAMPLING_INTERVAL, event);
      if (s != ERROR_SUCCESS)
          goto error;
  
      ret = RegisterWaitForSingleObject(
          &waitHandle,
          event,
          (WAITORTIMERCALLBACK)LoadAvgCallback,
          (PVOID)
          hCounter,
          INFINITE,
          WT_EXECUTEDEFAULT);
  
      if (ret == 0) {
          PyErr_SetFromWindowsErr(GetLastError());
          return NULL;
      }
  
      Py_RETURN_NONE;
  
  error:
      PyErr_SetExcFromWindowsErr(PyExc_OSError, 0);
      return NULL;
  }
  
  
  /*
   * Gets the emulated 1 minute, 5 minute and 15 minute load averages
   * (processor queue length) for the system.
   * `init_loadavg_counter` must be called before this function to engage the
   * mechanism that records load values.
   */
  PyObject *
  psutil_get_loadavg(PyObject *self, PyObject *args) {
      return Py_BuildValue("(ddd)", load_avg_1m, load_avg_5m, load_avg_15m);
  }
  