khchen / winim

Windows API, COM, and CLR Module for Nim

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to improve performance?

throwaway4rust opened this issue · comments

import winim/lean
import strformat except `&`

proc main =
  var sc = OpenSCManager(nil, nil, SC_MANAGER_ENUMERATE_SERVICE)

  if sc != 0:
    defer: CloseServiceHandle(sc)

    const
      srvType = SERVICE_WIN32
      srvState = SERVICE_STATE_ALL

    var bytesNeeded, srvCount, resumeHandle: DWORD

    # Use nil pointer in first call to avoid realloc the buffer later
    EnumServicesStatus(sc, srvType, srvState, nil, 0, &bytesNeeded, &srvCount,
      &resumeHandle)

    # Use string for the buffer, or you can use alloc() and then dealloc() later.
    var buffer = newString(bytesNeeded)

    # Cast the pointer to what EnumServicesStatus want.
    # Here &buffer = addr buffer[0]
    let lpService = cast[LPENUM_SERVICE_STATUS](&buffer)

    # We can access the low level c array easily by using Nim's UncheckedArray.
    let services = cast[ptr UncheckedArray[ENUM_SERVICE_STATUS]](lpService)

    EnumServicesStatus(sc, srvType, srvState, lpService, bytesNeeded,
      &bytesNeeded, &srvCount, &resumeHandle)

    echo fmt"Count of NT Services using EnumServicesStatus: {srvCount}"
    for i in 0..<srvCount:
      echo fmt"{services[i].lpServiceName}: {services[i].lpDisplayName}"

when isMainModule:
  main()

The following code when compiled with nim c -d:danger -d:release --gc:arc and tested with

Measure-Command { main.exe }

Takes 18ms on my machine.

Measure-Command { get-service }

Takes 3ms.

Is there any reason why or does anyone know how to improve performance?

commented

For other program, you may try adding --opt:speed and --passc:-flto. For this program, I don't think it can be improved anymore. Because I get the same result (about 20ms) if I comment out all the lines (compile an empty file).

Maybe powershell get-service is using some pre-allocation strategy to do only 1 call?
It seems odd that powershell commandlet can beat low level code like this and also by providing more output than the Nim code above.

BTW if you feel like this is not worth discussing if we simply do not know and cant find out feel free to close the issue 👍
Thanks a lot for winim it's really an amazing library!

measure-command { get-service | out-default }

Is the correct way to measure this commandlet as by default it's not measuring printing out on stdout.