如何制作基于文本的界面 (TUI/TLI) 来监控 OpenFOAM 求解器日志文件?
Posted
技术标签:
【中文标题】如何制作基于文本的界面 (TUI/TLI) 来监控 OpenFOAM 求解器日志文件?【英文标题】:How to make a text-based interface (TUI/TLI) for monitoring OpenFOAM solver log file? 【发布时间】:2018-08-29 10:01:33 【问题描述】:我正在集群上运行 OpenFOAM 模拟,它们需要几天时间才能完成。我正在寻找一种方法来监控流程并获得一些有意义的见解。我目前能做的就是使用
查看日志文件的尾部watch tail -n 15 log.log
来自here 我还发现了一个不错的 GnuPlot-grep 脚本:
set logscale y
set title "Residuals"
set ylabel 'Residual'
set xlabel 'Iteration'
plot "< cat log.log | grep 'Solving for Ux' | cut -d' ' -f9 | tr -d ','" title 'Ux' with lines,\
"< cat log.log | grep 'Solving for Uy' | cut -d' ' -f9 | tr -d ','" title 'Uy' with lines,\
"< cat log.log | grep 'Solving for Uz' | cut -d' ' -f9 | tr -d ','" title 'Uz' with lines,\
"< cat log.log | grep 'Solving for omega' | cut -d' ' -f9 | tr -d ','" title 'omega' with lines,\
"< cat log.log | grep 'Solving for k' | cut -d' ' -f9 | tr -d ','" title 'k' with lines,\
"< cat log.log | grep 'Solving for p' | cut -d' ' -f9 | tr -d ','" title 'p' with lines,\
"< cat log.log | grep 'Courant Number' | cut -d' ' -f9 | tr -d ','" title 'Courant Number mean' with lines,\
"< cat log.log | grep 'Courant Number' | cut -d' ' -f6 | tr -d ','" title 'Courant Number max' with lines
pause 1
reread
它从log.log
文件中提取信息,如果我在顶部某处添加set term dumb
,它可以在终端中绘图。但是,情节非常拥挤,丑陋,需要永远显示并且顺序打印到终端,而不是更新前一个。
在互联网上搜索我发现有一些不错的 python 库,例如 npyscreen/picotui、ncurses/blessed、Asciimatics、Urwid、Prompt Toolkit ... 用于创建 TUI/TLI。我想知道您是否可以帮助我了解如何创建基于文本的界面来显示基本信息以及所选值与时间的关系图。我想要几个面板。一个选择我想要绘制的变量,例如Courant Number mean
,另一个面板上有一个显示该变量与步进时间的图。和其他实时显示所有变量的最新值。我想到的应该类似于urwind's graph.py
example:
P.S.自从我发布了这个:
Here 我被介绍到 Termgraph 一个非常有趣的 python 库,以便在终端中获取一些图形。 我已经在 Urwid google 组中发布了这个想法。你可以关注the discussion here。 我发现PyFoam
的CaseBuilder
也使用了Urwid。另外here 我被告知 PyFoam 项目中的其他尝试,以从求解器获取一些不错的 TUI 信息。
【问题讨论】:
坚持使用 gnuplot,您可以尝试在每次刷新之前清除屏幕,例如在脚本开头的某处包含print "\033c"
。我能想到为什么这个脚本可能很慢的唯一原因是,对于每一帧,您处理整个日志文件 8 次。很可能您可以使用awk
或perl
魔术一次提取所需的数据。你能发布一个数据文件的sn-p吗?
@user8153 谢谢。日志文件的更新速度非常快。也许有办法只读取更新的部分?
我用于此类事情的一种方法是拥有一块 SYSV 或 POSIX 共享内存,计算进程会不断更新,然后 amy 监控进程可以简单地附加并获取他们想要的任何统计信息。现在,我可能会在 Redis 中填充我需要的数字,并让任何监控过程自行解决。 Redis 具有非常适合时间序列、队列的哈希、集合、排序集合,您还可以提供 TTL(生存时间),之后数据会自动删除,这样集合就不会变得太大。只是一个想法。
我没有要分享的要点,但这里有一些链接 tutorialspoint.com/redis/redis_overview.htm 和 redis.io/topics/data-types-intro 和 infoq.com/articles/redis-time-series
它是一个非常快速的内存中“数据结构服务器”,它为从 C/C++、php、Python、bash、Java 调用的客户端提供列表、字符串、哈希、集合。我建议您通过键值的集群软件将写入添加到 Redis,然后通过从 Redis(在 bash 或 Python 中)读取并可能使用 matplotlib 进行实时绘图来监控进度。
【参考方案1】:
如上面的 cmets 中所述,我为您制作了一些示例代码。它基于 Redis,我建议您在集群管理器节点上运行 Redis,该节点可能靠近集群的节点并且始终处于运行状态 - 因此非常适合统计数据收集服务。
示例代码是一个虚拟作业,用 Python 编写,以及一个用 bash
编写的监控例程,但该工作可以很容易地用 C/C++ 编写,监控例程在Perl - Redis 有各种各样的绑定 - 不要拘泥于一种语言。
即使你不会读Python,也很容易理解。有 3 个线程并行运行。只需将 Redis 中的string
更新为总经过的处理时间。另外两个使用时间序列数据更新 Redis lists
- 合成三角波 - 一个以 5 Hz 运行,另一个以 1 Hz 运行。
我使用了一个 Redis 字符串,其中变量不需要记录历史,而一个 Redis 列表则需要历史。其他数据结构可用。
在下面的代码中,唯一有趣的 3 行是:
# Connect to Redis server by IP address/name
r = redis.Redis(host='localhost', port=6379, db=0)
# Set a Redis string called 'processTime' to value `processsTime`
r.set('processTime', processTime)
# Push a value to left end of Redis list
r.lpush(RedisKeyName, value)
这是正在监视的虚拟作业。从它说的地方开始阅读
######
# Main
######
代码如下:
#!/usr/local/bin/python3
import redis
import _thread
import time
import os
import random
################################################################################
# Separate thread periodically updating the 'processTime' in Redis
################################################################################
def processTimeThread():
"""Calculate time since we started and update every so often in Redis"""
start = time.time()
while True:
processTime = int(time.time() - start)
r.set('processTime', processTime)
time.sleep(0.2)
################################################################################
# Separate thread generating a times series and storing in Redis with the given
# name and update rate
################################################################################
def generateSeriesThread(RedisKeyName, interval):
"""Generate a saw-tooth time series and log to Redis"""
# Delete any values from previous runs
r.delete(RedisKeyName)
value = 0
inc = 1
while True:
# Generate next value and store in Redis
value = value + inc
r.lpush(RedisKeyName, value)
if value == 0:
inc = 1
if value == 10:
inc = -1
time.sleep(interval)
################################################################################
# Main
################################################################################
# Connect to Redis on local host - but could just as easily be on another machine
r = redis.Redis(host='localhost', port=6379, db=0)
# Get start time of job in RFC2822 format
startTime=time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime())
# ... and set Redis string "startTime"
r.set('startTime',startTime)
# Get process id (pid)
pid=os.getpid()
# ... and set Redis string "pid""
r.set('pid',pid)
# Start some threads generating data
_thread.start_new_thread( processTimeThread, () )
_thread.start_new_thread( generateSeriesThread, ('seriesA', 0.2) )
_thread.start_new_thread( generateSeriesThread, ('seriesB', 1) )
# Hang around (with threads still running) till user presses a key
key = input("Press Return/Enter to stop.")
然后我在bash
中编写了一个连接到 Redis 的监控脚本,获取值并在终端上以 TUI(文本用户界面)的形式显示它们。您可以同样使用 Python、Perl 或 PHP,同样可以编写图形界面或基于 Web 的界面。
#!/bin/bash
################################################################################
# drawGraph
################################################################################
drawGraph()
top=$1 ; shift
data=( "$@" )
for ((row=0;row<10;row++)) ; do
((y=10-row))
((screeny=top+row))
line=""
for ((col=0;col<30;col++)) ; do
char=" "
declare -i v
v=$data[col]
[ $v -eq $y ] && char="X"
line="$line$char"
done
printf "$(tput cup $screeny 0)%s" "$line"
done
# Save screen and clear and make cursor invisible
tput smcup
tput clear
tput civis
# Trap exit
trap 'exit 1' INT TERM
trap 'tput rmcup; tput clear' EXIT
while :; do
# Get processid from Redis and display
pid=$(redis-cli <<< "get pid")
printf "$(tput cup 0 0)ProcessId: $pid"
# Get process start time from Redis and display
startTime=$(redis-cli <<< "get startTime")
printf "$(tput cup 1 0)Start Time: $startTime"
# Get process running time from Redis and display
processTime=$(redis-cli <<< "get processTime")
printf "$(tput cup 2 0)Running Time: $(tput el)$processTime"
# Display seriesA last few values
seriesA=( $(redis-cli <<< "lrange seriesA 0 30") )
printf "$(tput cup 5 0)seriesA latest values: $(tput el)"
printf "%d " "$seriesA[@]"
# Display seriesB last few values
seriesB=( $(redis-cli <<< "lrange seriesB 0 30") )
printf "$(tput cup 6 0)seriesB latest values: $(tput el)"
printf "%d " "$seriesB[@]"
drawGraph 8 "$seriesA[@]"
drawGraph 19 "$seriesB[@]"
# Put cursor at bottom of screen and tell user how to quit
printf "$(tput cup 30 0)Hit Ctrl-C to quit"
done
希望您能看到您可以非常轻松地从 Redis 中获取数据结构。这将在集群节点上的作业中设置processTime
变量:
processTime=$(redis-cli <<< "get processTime")
TUI 如下所示:
【讨论】:
哇。谢谢你。我需要一段时间来合成你的代码。我会的。点赞。以上是关于如何制作基于文本的界面 (TUI/TLI) 来监控 OpenFOAM 求解器日志文件?的主要内容,如果未能解决你的问题,请参考以下文章
menuconfig(基于文本(命令行)的图形化配置界面)是如何实现的
基于topeer 4412开发板 无界面linux文件系统的制作