Created
November 14, 2016 12:32
-
-
Save egonelbre/d4c8bcc7e61b32fd42bedb2d6847b57a to your computer and use it in GitHub Desktop.
shell32 load time measurement
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
rem don't use optimizations otherwise cl may remove Shell32 dependency | |
cl dynamic.cpp | |
cl static.cpp | |
cl none.cpp | |
del *.obj | |
rem compiled x64 https://dl.dropboxusercontent.com/u/4300994/Go/measure-shell32-loading.zip |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define WIN32_LEAN_AND_MEAN | |
#include <stdio.h> | |
#include <Windows.h> | |
#include <shellapi.h> | |
int WINAPI WinMain( | |
HINSTANCE hInstance, | |
HINSTANCE hPrevInstance, | |
LPSTR lpCmdLine, | |
int nCmdShow) | |
{ | |
HINSTANCE proc = LoadLibrary("shell32.dll"); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define WIN32_LEAN_AND_MEAN | |
#include <stdio.h> | |
#include <Windows.h> | |
#include <shellapi.h> | |
int WINAPI WinMain( | |
HINSTANCE hInstance, | |
HINSTANCE hPrevInstance, | |
LPSTR lpCmdLine, | |
int nCmdShow) | |
{ | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma comment(lib, "Shell32") | |
#define WIN32_LEAN_AND_MEAN | |
#include <stdio.h> | |
#include <Windows.h> | |
#include <shellapi.h> | |
int WINAPI WinMain( | |
HINSTANCE hInstance, | |
HINSTANCE hPrevInstance, | |
LPSTR lpCmdLine, | |
int nCmdShow) | |
{ | |
// to ensure that Shell32 gets actually linked | |
auto x = ShellExecute; | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"errors" | |
"flag" | |
"fmt" | |
"os" | |
"runtime" | |
"strings" | |
"syscall" | |
"time" | |
"unsafe" | |
"golang.org/x/sys/windows" | |
) | |
var ( | |
N = flag.Int("n", 1000, "number of measurements") | |
) | |
type Measurement struct { | |
N int | |
Elapsed time.Duration | |
Kernel time.Duration | |
User time.Duration | |
PageFault int | |
WorkingSet int | |
PagedPool int | |
NonPagedPool int | |
PageFileSize int | |
} | |
func (m *Measurement) Add(b *Measurement) { | |
m.N += b.N | |
m.Elapsed += b.Elapsed | |
m.Kernel += b.Kernel | |
m.User += b.User | |
m.PageFault += b.PageFault | |
m.WorkingSet += b.WorkingSet | |
m.PagedPool += b.PagedPool | |
m.NonPagedPool += b.NonPagedPool | |
m.PageFileSize += b.PageFileSize | |
} | |
func (m *Measurement) Print() { | |
fmt.Printf("Elapsed %3.6fms\n", (m.Elapsed/time.Duration(m.N)).Seconds()*1000) | |
fmt.Printf("Kernel %3.6fms\n", (m.Kernel/time.Duration(m.N)).Seconds()*1000) | |
fmt.Printf("User %3.6fms\n", (m.User/time.Duration(m.N)).Seconds()*1000) | |
fmt.Printf("PageFault %3v KB\n", m.PageFault/m.N) | |
fmt.Printf("WorkingSet %3v KB\n", m.WorkingSet/m.N) | |
fmt.Printf("PagedPool %3v KB\n", m.PagedPool/m.N) | |
fmt.Printf("NonPagedPool %3v KB\n", m.NonPagedPool/m.N) | |
fmt.Printf("PageFileSize %3v KB\n", m.PageFileSize/m.N) | |
} | |
func filetimeToDuration(ft windows.Filetime) time.Duration { | |
nsec := int64(ft.HighDateTime)<<32 + int64(ft.LowDateTime) | |
return time.Duration(nsec*100) * time.Nanosecond | |
} | |
func Inspect(pid windows.Handle) (*Measurement, error) { | |
m := &Measurement{N: 1} | |
var creation, exit, kernel, user windows.Filetime | |
if err := windows.GetProcessTimes(pid, &creation, &exit, &kernel, &user); err != nil { | |
return nil, err | |
} | |
m.Elapsed = filetimeToDuration(exit) - filetimeToDuration(creation) | |
m.Kernel = filetimeToDuration(kernel) | |
m.User = filetimeToDuration(user) | |
var pmc ProcessMemoryCounters | |
if err := GetProcessMemoryInfo(pid, &pmc); err != nil { | |
return nil, err | |
} | |
m.PageFault = int(pmc.PageFaultCount) | |
m.WorkingSet = int(pmc.PeakWorkingSetSize) | |
m.PagedPool = int(pmc.QuotaPeakPagedPoolUsage) | |
m.NonPagedPool = int(pmc.QuotaPeakNonPagedPoolUsage) | |
m.PageFileSize = int(pmc.PeakPagefileUsage) | |
return m, nil | |
} | |
func MeasureProcess(args string) (*Measurement, error) { | |
si := &windows.StartupInfo{} | |
pi := &windows.ProcessInformation{} | |
argsp := windows.StringToUTF16Ptr(args) | |
defer runtime.KeepAlive(argsp) | |
err := windows.CreateProcess(nil, argsp, nil, nil, false, 0, nil, nil, si, pi) | |
if err != nil { | |
return &Measurement{}, err | |
} | |
defer windows.CloseHandle(pi.Thread) | |
defer windows.CloseHandle(pi.Process) | |
ev, err := windows.WaitForSingleObject(pi.Process, windows.INFINITE) | |
if err != nil { | |
return &Measurement{}, err | |
} | |
if ev != windows.WAIT_OBJECT_0 { | |
return &Measurement{}, errors.New("cannot wait for process") | |
} | |
return Inspect(pi.Process) | |
} | |
func main() { | |
flag.Parse() | |
args := strings.Join(flag.Args(), " ") | |
var total Measurement | |
for i := 0; i < *N; i++ { | |
m, err := MeasureProcess(args) | |
if err != nil { | |
fmt.Fprintln(os.Stderr, err) | |
continue | |
} | |
total.Add(m) | |
} | |
total.Print() | |
} | |
// psapi | |
var ( | |
modpsapi = windows.NewLazySystemDLL("psapi.dll") | |
procGetProcessMemoryInfo = modpsapi.NewProc("GetProcessMemoryInfo") | |
) | |
type ProcessMemoryCounters struct { | |
CB uint32 | |
PageFaultCount uint32 | |
PeakWorkingSetSize uintptr | |
WorkingSetSize uintptr | |
QuotaPeakPagedPoolUsage uintptr | |
QuotaPagedPoolUsage uintptr | |
QuotaPeakNonPagedPoolUsage uintptr | |
QuotaNonPagedPoolUsage uintptr | |
PagefileUsage uintptr | |
PeakPagefileUsage uintptr | |
} | |
func GetProcessMemoryInfo(h windows.Handle, pmc *ProcessMemoryCounters) (err error) { | |
r1, _, e1 := syscall.Syscall(procGetProcessMemoryInfo.Addr(), 3, uintptr(h), uintptr(unsafe.Pointer(pmc)), uintptr(unsafe.Sizeof(*pmc))) | |
if r1 == 0 { | |
if e1 != 0 { | |
err = error(e1) | |
} else { | |
err = syscall.EINVAL | |
} | |
} | |
return | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment