GPU 사용량 출력하기

스프레드시트에 GPU 사용량 자동 문서화 하기

알 수 없는 사용자 2021. 11. 8. 16:49
반응형

연구실에 서버가 여러대가 있다.

각 서버의 GPU 사용량을 스프레드시트에 자동으로 업데이트 하면 좋을 것 같아 만들어 봤다.

 

대략 이런 느낌으로 업데이트 되도록 했다.

누군가 관심이 생긴다면 보고 따라해보면 좋을 듯 하다.

 

 

전체적인 과정은 다음과 같다.

 

1. 각 서버에서 일정 시간마다 코드를 실행시킨다.

2. 실행된 코드는 스프레드 시트 api로 웹 request를 보낸다.

3. request를 받으면 자동으로 입력되도록 한다.

 

코드에 사용된 언어는 python이며, 각자 잘 하는 언어를 사용해도 무방하다.

 

자 그러면 우선 서버에서 실행되는 코드부터 보도록 하자.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import os
from re import template
import requests
 
import argparse
 
parser = argparse.ArgumentParser(description='PyTorch GPU USAGE')
parser.add_argument('--n', default=0, type=int,
                    metavar='N', help='gpu num')
result_str = os.popen('nvidia-smi | grep MiB').read()
 
lines = result_str.split('\n')
 
usage_list = []
max_list = []
temperature_list = []
user_list = []
 
for line in lines:
    tmp = line.split('|')
    if len(tmp) == 5:
        usage = tmp[2].replace(' ''')
        temperature_list.append(tmp[1].split()[1])        
        usage_list.append(usage.split('/')[0])
        max_list.append(usage.split('/')[1])
    if len(tmp) == 3:
        foruser = tmp[1].split()
        if int(foruser[6].split('MiB')[0]) > 100:
            result_user = os.popen(f'ps -u -p {foruser[3]}').read()
            user_list.append(result_user.split('\n')[1].split()[0])
            
gpu_num = len(usage_list)
user_num = len(user_list)
 
params = {}
params['gpu_num'= gpu_num
params['user_num'= user_num
for i in range(gpu_num):
    params[f'usage{i}'= usage_list[i]
    params[f'max{i}'= max_list[i]
    params[f"temperature{i}"= temperature_list[i]
for i in range(user_num):
    params[f'user{i}'= user_list[i]
 
args = parser.parse_args()
params["line"= args.n
 
 
URL = "https://script.google.com/macros/s/YOURSCRIPTID/exec"
res = requests.post(URL, data=params)
 
cs

 

 

 

어려울건 없다.

 

os.popen은 cmd 명령어를 실행해주고 read()를 통해 그 결과를 받아와 준다.

스프레드 시트에 입력하고 싶은 것들은 총 3가지다.

1. GPU 온도

2. GPU 현재용량 / 최대용량

3. 코드를 사용하고 있는 사용자.

 

1, 2번은 nvidia-smi를 통해 얻을 수 있으며

3번은 100MiB 이상 사용하고 있는 프로그램의 PID를 얻어 해당 PID가 어떤 계정에서 돌고있는 프로그램인지 얻어냈다.

 

이후 params를 통해 POST를 하여 넘겨준다.

이 때 배열은 안넘어가길래 궁여지책으로 딕셔너리의 키값에 번호를 붙여 넘겼다...

좋은 방법이 있을 텐데 나는 초보라 잘 모르겠다.

 

그 다음엔 스프레드 시트에서 해당 데이터를 받아오는 부분이다.

스프레드 시트를 하나 연 뒤, 도구->스크립트 편집기를 클릭한다.

 

필자는 이런 코드를 사용했다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
function doGet(e){
  return ContentService.createTextOutput("test").setMimeType(ContentService.MimeType.TEXT);
}
 
function doPost(e){
  var ss = SpreadsheetApp.openByUrl("https://docs.google.com/spreadsheets/d/YOURSHEETURL/edit");
  // var sheet = ss.getSheetByName('GPU'); // be very careful ... it is the sheet name .. so it should match 
  var activesheet = ss.getActiveSheet();
  var line = e.parameter["line"]*3 + 4
 
  for (var i=0; i<e.parameter["gpu_num"]; i++){
    var tmp = "usage" + i
    var maximum = "max"+i
    var temperature = "temperature"+i
 
    activesheet.getRange(line, 6+i).setValue(e.parameter[tmp]+"/"+e.parameter[maximum] +" ("+e.parameter[temperature]+")");
 
  }
 
  for (var i=0; i<10; i++){
    if (i<e.parameter["user_num"]){
      var tmp = "user" + i
      activesheet.getRange(line, 11+i).setValue(e.parameter[tmp]);
    }
    else{
      activesheet.getRange(line, 11+i).setValue("");
    }
  }
  
  return ContentService.createTextOutput("Success").setMimeType(ContentService.MimeType.TEXT);
 
}
cs

중요한 함수는 doPost 이다.

인자로 받아온 e.parameter에 python코드에서 넘긴 데이터가 들어가있다.

하나씩 빼서 원하는 곳에 넣어준다.

참고로 getRange(줄, 열) 이라 생각하면 된다.

 

이 스크립트 코드를 배포를 해줘야 한다. 배포를 하면 웹앱 주소가 나올텐데 해당 주소를 파이썬 코드에 붙여넣고 실행시켜보자.

 

이렇게 쓴 결과

 잘 출력된다.

 

참고로 밑의 막대바는 GPU사용정도를 표현한 것이고, 다음과 같이 만들었다.

 

=SPARKLINE(((LEFT(SUBSTITUTE(Left(G16, Find("(",G16)-2),"MiB",""), FIND("/",SUBSTITUTE(Left(G16, Find("(",G16)-2),"MiB",""))-1)*100/MID(SUBSTITUTE(Left(G16, Find("(",G16)-2),"MiB",""), FIND("/",SUBSTITUTE(Left(G16, Find("(",G16)-2),"MiB",""))+1, 100))),{"charttype","bar"; "max", 100})

 

해석은.. 알아서 하길 바란다.

 

자 이제 주기적으로 서버에서 python 코드를 실행시켜줘야 한다.

간단하다.

 

서버에 다음 코드를 입력한다.

 

crontab -e

 

그리고 밑의 코드를 입력한다.

5/N * * * * /usr/bin/python3.8 /GPU_usage.py --n 5

 

5/N은 5분마다 한번씩 실행하겠다는 이야기이다. 자세한 것은 crontab 사용법을 찾아보길 바란다.

중요한 점은 python 3.7 이상 버전의 절대경로를 넣어줘야 한다는 것이다.

(필자의 경우 3.8의 절대경로를 넣어줬다.)

그리고 그 뒤에 만들어둔 python 코드를 넣어준다.

 

인자로 --n 을 통해 숫자를 넘겨주는데, 이 숫자는 몇번째 서버인지를 나타낸다.

스프레드 시트에 해당 숫자만큼 밑으로 이동해 채워넣어주고 있다. (파이썬 코드와 script 코드를 참고하자)

 

이후 sudo service cron start 을 실행시켜 활성화를 시켜준다.

(이러면 서버가 꺼졌다 켜져도 계속 실행된다)

 

뭘 하려 했든 이 전체적인 흐름과 코드들이 도움이 되길 바란다.

 

나는 연구실 서버 여러대에 모두 코드를 넣어두고 실행시켜놨다. 매 5분마다 한번씩 업데이트 된다.

반응형