Jupyter notebook Jupyter笔记本:每个笔记本的内存使用情况

Jupyter notebook Jupyter笔记本:每个笔记本的内存使用情况,jupyter-notebook,Jupyter Notebook,由于用户从未关闭旧笔记本电脑,我实验室服务器(Ubuntu)上的内存不断被填满。我想更好地了解每个笔记本占用了多少内存。我可以总结每个用户运行的所有jupyter笔记本的内存使用情况(粗略),但我想得到每个笔记本的总内存使用情况,这样我就可以关闭那些特定的内存占用(或告诉其他用户关闭他/她的)。我很快把下面的代码放在一起,得到了大约mem。每个jupyter内核的使用率,但我不知道如何将内核ID与特定笔记本关联 import os import pwd import pandas as pd

由于用户从未关闭旧笔记本电脑,我实验室服务器(Ubuntu)上的内存不断被填满。我想更好地了解每个笔记本占用了多少内存。我可以总结每个用户运行的所有jupyter笔记本的内存使用情况(粗略),但我想得到每个笔记本的总内存使用情况,这样我就可以关闭那些特定的内存占用(或告诉其他用户关闭他/她的)。我很快把下面的代码放在一起,得到了大约mem。每个jupyter内核的使用率,但我不知道如何将内核ID与特定笔记本关联

import os
import pwd
import pandas as pd

UID   = 1
EUID  = 2

pids = [pid for pid in os.listdir('/proc') if pid.isdigit()]

df = []
for pid in pids:
    try:
        ret = open(os.path.join('/proc', pid, 'cmdline'), 'rb').read()
    except IOError: # proc has already terminated
        continue

    # jupyter notebook processes
    if len(ret) > 0 and 'share/jupyter/runtime' in ret:
        process = psutil.Process(int(pid))
        mem = process.memory_info()[0] 

        # user name for pid
        for ln in open('/proc/%d/status' % int(pid)):
            if ln.startswith('Uid:'):
                uid = int(ln.split()[UID])
                uname = pwd.getpwuid(uid).pw_name

        # user, pid, memory, proc_desc
        df.append([uname, pid, mem, ret])

df = pd.DataFrame(df)
df.columns = ['user', 'pid', 'memory', 'proc_desc']
df

我似乎已经为自己的问题找到了一个可行的解决方案:

import os
import pwd
import psutil
import re
import string
import json
import urllib2
import pandas as pd

UID   = 1
EUID  = 2
regex = re.compile(r'.+kernel-(.+)\.json')

pids = [pid for pid in os.listdir('/proc') if pid.isdigit()]

# memory info from psutil.Process
df_mem = []
for pid in pids:
    try:
        ret = open(os.path.join('/proc', pid, 'cmdline'), 'rb').read()
    except IOError: # proc has already terminated
        continue

    # jupyter notebook processes
    if len(ret) > 0 and 'share/jupyter/runtime' in ret:
        # kernel
        kernel_ID = re.sub(regex, r'\1', ret)
        kernel_ID = filter(lambda x: x in string.printable, kernel_ID)

        # memory
        process = psutil.Process(int(pid))
        mem = process.memory_info()[0] / float(1e9)


        # user name for pid
        for ln in open('/proc/{}/status'.format(int(pid))):
            if ln.startswith('Uid:'):
                uid = int(ln.split()[UID])
                uname = pwd.getpwuid(uid).pw_name

        # user, pid, memory, kernel_ID
        df_mem.append([uname, pid, mem, kernel_ID])

df_mem = pd.DataFrame(df_mem)
df_mem.columns = ['user', 'pid', 'memory_GB', 'kernel_ID']


# notebook info from assessing ports
df_nb = []
for port in xrange(5000,30000):
    sessions = None
    try:
        url = 'http://127.0.0.1:{}/api/sessions'.format(port)
        sessions = json.load(urllib2.urlopen(url))
    except urllib2.URLError:
        sessions = None

    if sessions:
        for sess in sessions:
            kernel_ID = str(sess['kernel']['id'])
            notebook_path = sess['notebook']['path']
            df_nb.append([port, kernel_ID, notebook_path])

df_nb = pd.DataFrame(df_nb)
df_nb.columns = ['port', 'kernel_ID', 'notebook_path']


# joining tables
df = pd.merge(df_nb, df_mem, on=['kernel_ID'], how='inner')
df.sort(['memory_GB'], ascending=False)

我在可移植性和速度方面做了一些改进

主要是,只检查笔记本电脑运行的端口,检查不同的主机名选项,改进内核进程检查,检查ipython或jupyter

import argparse
进口稀土
导入子流程
作为pd进口熊猫
导入psutil
导入请求
进口表格
kernel\u regex=re.compile(r“+kernel-(.+)\.json”)
notebook_regex=re.compile(r)(https?:/([^:/]):?(\d+)/(\?令牌=([a-z0-9]+)?)
def get_proc_info():
pids=psutil.pids()
#来自psutil.Process的内存信息
df_mem=[]
对于pid中的pid:
尝试:
proc=psutil.Process(pid)
cmd=”“.join(proc.cmdline())
除psutil.NoSuchProcess外:
持续
如果len(cmd)>0和(cmd中的“jupyter”或cmd中的“ipython”)以及cmd中的“kernel”:
#内核
kernel\u ID=re.sub(kernel\u regex,r“\1”,cmd)
#记忆
mem=proc.memory\u info()[0]/float(1e9)
uname=proc.username()
#用户、pid、内存、内核\u ID
df_mem.append([uname,pid,mem,kernel_ID])
df_mem=pd.DataFrame(df_mem)
df_mem.columns=[“用户”、“pid”、“内存\u GB”、“内核\u ID”]
返回df_mem
def让_运行_笔记本():
笔记本=[]
对于subprocess.Popen中的n(
[“jupyter”、“notebook”、“list”],stdout=subprocess.PIPE
).stdout.readlines()[1:]:
match=re.match(notebook_regex,n.decode())
如果匹配:
基本url、主机、端口、令牌=match.groups()
append({“base\u url”:base\u url,“token”:token})
其他:
打印(“未知格式:{}”。格式(n.decode())
归还笔记本
def获取会话信息(密码=无):
df_nb=[]
内核=[]
对于get_running_notebook()中的笔记本:
s=请求。会话()
如果笔记本[“令牌”]不是无:
s、 获取(笔记本[“基本url”]+“/?令牌=”+笔记本[“令牌”])
其他:
#访问基本url以获取会话cookie
s、 获取(笔记本[“基本url”])
如果密码不是“无”:
#似乎jupyter认证过程已更改,需要先获取cookie,
#然后将cookie添加到使用密码发送的数据中
数据={“密码”:密码}
数据更新(s.cookies)
s、 post(笔记本[“基本url”]+“/登录”,数据=数据)
res=s.get(笔记本[“基本url”]+“/api/sessions”)
如果资源状态\u代码!=200:
引发异常(res.json())
对于res.json()中的SES:
kernel_ID=sess[“kernel”][“ID”]
如果内核ID不在内核中:
内核={
“内核ID”:内核ID,
“内核名称”:sess[“内核”][“名称”],
“内核状态”:sess[“内核”][“执行状态”],
“内核连接”:sess[“内核”][“连接”],
#“笔记本url”:笔记本[“基本url”]+“/notebook/”+sess[“id”],
“笔记本路径”:sess[“路径”],
}
内核更新(笔记本)
df_nb.append(内核)
append(kernels\u ID)
df_nb=局部数据帧(df_nb)
del df_nb[“令牌”]
返回df_nb
def parse_args():
parser=argparse.ArgumentParser(description=“查找内存使用情况”)
parser.add_参数(“--password”,help=“password(仅当密码受保护时才需要)”)
返回parser.parse_args()
def main(密码=无,打印ascii=假):
df_mem=get_proc_info()
df_nb=获取会话信息(密码)
#连接表
df=pd.merge(df_nb,df_mem,on=[“内核ID”],how=“内部”)
df=df.sort\u值(“内存\u GB”,升序=False)。重置\u索引(drop=True)
如果使用ascii打印:
打印(tablate.tablate(df,headers=(df.columns.tolist()))
返回df
如果名称=“\uuuuu main\uuuuuuuu”:
args=vars(parse_args())
main(args[“password”],print_ascii=True)
我可能会在这个时候继续对此进行更新


编辑:代码已更新,可以使用令牌身份验证与较新版本的Jupyter一起工作,只利用psutil使其与Windows兼容,并且可以在Python 3上工作。

我无法运行此。。由于未找到带有错误的模块
PackageNotFoundError:当前通道中缺少包:-pwd
。不需要
pwd
的任何其他解决方案。我使用anaconda python 2.7在windows服务器上运行。我无法运行此。。由于未找到带有错误的模块
PackageNotFoundError:当前通道中缺少包:-pwd
。不需要
pwd
的任何其他解决方案。我使用anaconda python 2.7在windows服务器上运行。@iLightower-hmmm,我怀疑这是否能在windows上运行。它从proc获取有关进程的大部分信息,这是一种Unix方式,用于存储有关运行进程、服务等的数据。这可能为您提供了一个起点。@iLightower我已将其更新为不使用
pwd
/proc
。相反,它只使用
psutil
,它应该是可移植的,并且可以在Windows上工作。@a如果在ifmain中调用它时,您应该在主参数中添加password=args([“password”])。否则,它可能会被解释为