无法打开执行命令的实时记忆分析的`proc/pid]/status”
动机:
我一直在尝试分析代码执行的时间和内存消耗,并在达到任一参数的限制后终止正在执行的命令。
障碍:
我正在尝试编写一个 go 例程,通过每隔 100 毫秒间隔从 proc/[pid]/status 读取状态来持续监控进程内存消耗。
命令执行代码块
// code block:
// define a resource group with limited memory
rlimit := syscall.Rlimit{
Cur: uint64(2048 * 1024 * 1024), // 1GB
Max: uint64(2048 * 1024 * 1024), // 1GB
}
// Create a new command
cmd = exec.Command("/bin/bash", "-c", execCmd)
// Set command as separate process
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
// Set resource limit
err = syscall.Setrlimit(syscall.RLIMIT_AS, &rlimit)
if err != nil {
log.Fatal("Error in setting rlimit: ", err)
}
start := time.Now()
内存使用计算实用程序
Go 库 我正在使用 pidusage
// memoryUsage returns the memory usage of a process in bytes.
func memoryUsage(pid int) (float64, error) {
stats, err := pidusage.GetStat(pid)
if err != nil {
return 0, err
}
return stats.Memory / 1024, nil
}
Go-routine
// call the function monitorMemory every 10 milli-seconds
// Get the current memory usage in the background
go func(start time.Time) {
// Print the memory usage every 10 milli-seconds
for {
// Get the current memory usage
memoryUsage, err := memoryUsage(cmd.Process.Pid)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
// kill process if memory usage is greater than 2MB
if memoryUsage > 500*1024 {
err := syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL)
if err != nil {
log.Fatal(err)
os.Exit(1)
}
result.ErrorCode = "MLE"
result.RunTimeErr = "Memory Limit Exceeded. Took more than 500MB."
result.MemoryUsage = memoryUsage
result.RunTime = time.Since(start)
printformattedResult(*result)
// Exit the loop
break
}
time.Sleep(1 * time.Nanosecond)
}
}(start)
如果将内存限制设置为小于 50 MB,但一旦我增加了监视限制并等待我开始,该方法效果很好得到的错误为:
open /proc/110050/stat: no such file or directory
其他尝试过方法:
我还尝试将内存使用情况读取为 float64(cmd.ProcessState.SysUsage((*syscall.Rusage).Maxrss)
但由于某种原因,go 例程会抛出错误“未找到内存地址”。对 go-routine 没有非常深入的了解,但我认为这可能是由于它试图访问单独运行的子进程。
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x10 pc=0x4bb794]
goroutine 33 [running]:
os.(*ProcessState).sysUsage(...)
/usr/local/go/src/os/exec_posix.go:96
os.(*ProcessState).SysUsage(...)
/usr/local/go/src/os/exec.go:175
main.main.func2({0x0, 0x0, 0x5a0360})
/path/to/my/go/file.go:149 +0x74
created by main.main
/path/to/my/go/file.go:145 +0x7cf
Motive:
I have been trying to profile code execution for time as well as memory consumption and kill the executing command once a limit for either parameter is reached.
Roadblock:
I am trying to write a go-routine that constantly monitors the process memory consumption by reading the status from proc/[pid]/status
at every 100-millisecond interval.
Command Execution Code Block
// code block:
// define a resource group with limited memory
rlimit := syscall.Rlimit{
Cur: uint64(2048 * 1024 * 1024), // 1GB
Max: uint64(2048 * 1024 * 1024), // 1GB
}
// Create a new command
cmd = exec.Command("/bin/bash", "-c", execCmd)
// Set command as separate process
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
// Set resource limit
err = syscall.Setrlimit(syscall.RLIMIT_AS, &rlimit)
if err != nil {
log.Fatal("Error in setting rlimit: ", err)
}
start := time.Now()
Memory Usage calculation Utility
Go Library I am using pidusage
// memoryUsage returns the memory usage of a process in bytes.
func memoryUsage(pid int) (float64, error) {
stats, err := pidusage.GetStat(pid)
if err != nil {
return 0, err
}
return stats.Memory / 1024, nil
}
Go-routine
// call the function monitorMemory every 10 milli-seconds
// Get the current memory usage in the background
go func(start time.Time) {
// Print the memory usage every 10 milli-seconds
for {
// Get the current memory usage
memoryUsage, err := memoryUsage(cmd.Process.Pid)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
// kill process if memory usage is greater than 2MB
if memoryUsage > 500*1024 {
err := syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL)
if err != nil {
log.Fatal(err)
os.Exit(1)
}
result.ErrorCode = "MLE"
result.RunTimeErr = "Memory Limit Exceeded. Took more than 500MB."
result.MemoryUsage = memoryUsage
result.RunTime = time.Since(start)
printformattedResult(*result)
// Exit the loop
break
}
time.Sleep(1 * time.Nanosecond)
}
}(start)
The approach works fine If set a memory limit for less than 50 MB but once I increase the limit to monitor and wait for I start getting the error as:
open /proc/110050/stat: no such file or directory
Other Tried approaches:
I also tried reading memory usage as float64(cmd.ProcessState.SysUsage((*syscall.Rusage).Maxrss)
but for some reason go routine throws an error as `memory address not found. I do not have very in-depth knowledge of go-routine but I assumed this might be due to it trying to access a child process that is running separately.
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x10 pc=0x4bb794]
goroutine 33 [running]:
os.(*ProcessState).sysUsage(...)
/usr/local/go/src/os/exec_posix.go:96
os.(*ProcessState).SysUsage(...)
/usr/local/go/src/os/exec.go:175
main.main.func2({0x0, 0x0, 0x5a0360})
/path/to/my/go/file.go:149 +0x74
created by main.main
/path/to/my/go/file.go:145 +0x7cf
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论