From: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
To: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Cc: "linux-mm@kvack.org" <linux-mm@kvack.org>,
"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>
Subject: [RFC][PATCH ex/9] for debug
Date: Fri, 3 Apr 2009 17:24:53 +0900 [thread overview]
Message-ID: <20090403172453.3a229bb7.kamezawa.hiroyu@jp.fujitsu.com> (raw)
In-Reply-To: <20090403170835.a2d6cbc3.kamezawa.hiroyu@jp.fujitsu.com>
[-- Attachment #1: Type: text/plain, Size: 396 bytes --]
This mail attaches a patch and scirpt for debug.
soft_limit_show_prio.patch is for showing priority in memory.stat file.
I wonder I should add this to patch series or now...
cgroup.rb and ctop.rb is my personal ruby script, an utility to manage cgroup.
I sometimes use this. place both files to the same directory and run ctop.rb
#ruby ctop.rb
help will show this is for what.
Thanks,
-Kame
[-- Attachment #2: soft_limit_show_prio.patch --]
[-- Type: application/octet-stream, Size: 698 bytes --]
From: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Show internal control information of soft limit when DEBUG_VM is on.
Signed-off-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
---
mm/memcontrol.c | 1 +
1 file changed, 1 insertion(+)
Index: softlimit-test2/mm/memcontrol.c
===================================================================
--- softlimit-test2.orig/mm/memcontrol.c
+++ softlimit-test2/mm/memcontrol.c
@@ -2617,6 +2617,7 @@ static int mem_control_stat_show(struct
#ifdef CONFIG_DEBUG_VM
cb->fill(cb, "inactive_ratio",
calc_inactive_ratio(mem_cont, NULL, NULL));
+ cb->fill(cb, "soft_limit_prio", mem_cont->soft_limit_priority);
{
int nid, zid;
[-- Attachment #3: cgroup.rb --]
[-- Type: application/octet-stream, Size: 10798 bytes --]
require 'find'
$subsys_array = Array.new
$allsubsys = Hash.new
$allmounts = Hash.new
class Sub_system
def initialize(name, mount, option)
@name = name
@mount= mount
@hierarchy = Array.new
if (option =~ /.*noprefix.*/) then
@prefix =""
else
@prefix = name +"."
end
@option = option
@writable_files = Array.new
end
def mount_point
@mount
end
def type
@name
end
def myfile(name, attr)
name + "/" + @prefix + attr
end
def option
@option
end
#
# walk directroy tree and add Cgroups to hash.
#
def reload
@hierarchy.clear
len = @mount.size
Find.find(@mount) do |file|
if File.directory?(file) then
@hierarchy.push(file);
end
end
end
def each_cgroup(&block)
@hierarchy.each(&block)
end
def ent(id)
if (id < 0) then return nil
end
return @hierarchy.at(id)
end
def size
@hierarchy.size
end
def stat (name)
[["Not implemented", ""]]
end
def each_writable_files(name)
@writable_files.each {|x| yield myfile(name,x)}
end
def tasks(name)
list=Array.new
begin
File.open(name+"/tasks", "r") do |file|
file.each_line do |x|
x.chomp!
list.push(x)
end
end
rescue
return nil
end
return list
end
end
def read_oneline_file(filename)
val=nil
begin
f = File.open(filename, "r")
line = f.readline
val = line.to_i
rescue
throw :readfailure,false
ensure
f.close if f != nil
end
return val
end
#
#for CPU subsystem
#
class Cpu_Subsys < Sub_system
def initialize(mount, option)
super("cpu", mount, option)
@writable_files += ["shares"]
end
def read_share (name)
ret = nil
catch :readfailure do
val = read_oneline_file(myfile(name,"shares"))
return [val.to_s, val.to_s+" (100%)"] if (name == @mount)
all=0
dirname = File.dirname(name)
Dir.foreach(dirname) do |x|
next if ((x == ".") || (x == ".."))
x = "#{dirname}/#{x}"
next unless File.directory?(x)
next unless File.exist?(myfile(name,"shares"))
got = read_oneline_file(myfile(name,"shares"))
all+=got
end
share=sprintf("%d (%.1f%%)", all, val*100.0/all)
ret = [val.to_s, share]
end
return ret
end
def stat(name)
level=0
data = Array.new
pos = @mount
name_array = Array.new
loop do
name_array.push(name)
break if name == @mount
name = File.dirname(name)
end
name_array.reverse!
name_array.each do |x|
val = read_share(x)
if val == nil then
data = nil
break
end
str = sprintf("%5s / %s", val[0], val[1])
data.push([x, str])
end
return data if (data != nil && data.size > 0)
return nil
end
end
#
#for CPUacct subsystem
#
class Cpuacct_Subsys < Sub_system
def initialize(mount, option)
super("cpuacct", mount, option)
end
def stat(name)
data = Array.new
catch :read_failure do
val = read_oneline_file(myfile(name, "usage"))
data.push(["All", val.to_s])
begin
f = File.open(myfile(name,"usage_percpu"), "r")
id=0
line = f.readline
while (line =~/\d+/) do
line =$'
data.push(["cpu"+id.to_s, $&])
id += 1
end
rescue
data.clear
ensure
f.close if f != nil
end
return data if data.size > 0
return nil
end
end
end
#
# For cpuset
#
class Cpuset_Subsys < Sub_system
def initialize(mount, option)
super("cpuset", mount, option)
@elements =["cpu_exclusive","cpus","mems", "mem_exclusive","mem_hardwall",
"memory_migrate", "memory_pressure", "memory_pressure_enabled",
"memory_spread_page","memory_spread_slab",
"sched_load_balance","sched_relax_domain_level"]
@writable_files += @elements
end
def stat(name)
data = Array.new
for x in @elements
begin
filename = myfile(name, x)
next unless (File.file?(filename))
File.open(filename, "r") do | file |
str = file.readline
str.chomp!
case x
when "cpus", "mems"
str = "empty" if (str == "")
end
data.push([x,str])
end
rescue
#data = nil
break
end
end
return data
end
end
#
#for Memory Subsys
#
def convert_bytes(bytes, precise)
case
when (precise == 0) && (bytes > 64 * 1024*1024*1024*1024)
sprintf("Unlimited")
when (precise == 0) && (bytes > 1024*1024*1024*1024)
sprintf("%dT",bytes/1024/1024/1024/1024)
when (precise == 0) && (bytes > 1024*1024*1024)
sprintf("%dG", bytes/1024/1024/1024)
when (bytes > 1024*1024)
sprintf("%dM", bytes/1024/1024)
when (bytes > 1024)
sprintf("%dk", bytes/1024)
else
sprintf("%d", bytes)
end
end
#
#for Memory Subsystem
#
class Memory_Subsys < Sub_system
def initialize(mount, option)
super("memory", mount, option)
if (File.exist?("#{mount}/memory.memsw.usage_in_bytes")) then
@memsw=true
else
@memsw=false
end
@writable_files += ["limit_in_bytes", "use_hierarchy","swappiness", "soft_limit_in_bytes"]
if (@memsw) then
@writable_files += ["memsw.limit_in_bytes"]
end
end
#
# Find a root directroy of hierarchy.
#
def find_hierarchy_root(name)
cur=[name, File.dirname(name)]
ret=@mount
while (cur[0] != @mount)
ret="hoge"
under = read_oneline_file("#{cur[1]}/memory.use_hierarchy")
if (under == 0) then
return cur[0]
end
cur[0] = cur[1]
cur[1] = File.dirname(cur[1])
end
return ret
end
#
# Generate an array for reporintg status
#
def stat(name)
data = Array.new
success = catch(:readfailure) do
under =read_oneline_file(myfile(name,"use_hierarchy"))
if (under == 1) then
str=find_hierarchy_root(name)
if (str != name) then
str="under #{str}"
under=2
else
str="hierarchy ROOT"
end
else #Not under hierarchy
str=""
end
ent = ["Memory Subsys", str]
data.push(ent)
# Limit and Usage
x=Array.new
x.push("Usage/Limit")
bytes = read_oneline_file(myfile(name,"usage_in_bytes"))
usage = convert_bytes(bytes, 1)
if (@memsw) then
bytes = read_oneline_file(myfile(name,"memsw.usage_in_bytes"))
usage2 = convert_bytes(bytes, 1)
usage = "#{usage} (#{usage2})"
end
bytes = read_oneline_file(myfile(name,"limit_in_bytes"))
limit = convert_bytes(bytes, 0)
usage = "#{usage} / #{limit}"
if (@memsw) then
bytes = read_oneline_file(myfile(name,"memsw.limit_in_bytes"))
limit2 = convert_bytes(bytes, 0)
usage = "#{usage} (#{limit2})"
end
x.push(usage)
data.push(x)
# MAX USAGE
x = Array.new
x.push("Max Usage")
bytes = read_oneline_file(myfile(name, "max_usage_in_bytes"))
usage = convert_bytes(bytes, 1)
if (@memsw) then
bytes = read_oneline_file(myfile(name,"memsw.max_usage_in_bytes"))
usage2 = convert_bytes(bytes, 1)
usage = "#{usage} (#{usage2})"
end
x.push(usage)
data.push(x)
# soft limit
x = Array.new
x.push("Soft limit")
bytes = read_oneline_file(myfile(name, "soft_limit_in_bytes"))
usage = convert_bytes(bytes, 1)
x.push(usage)
data.push(x)
# failcnt
x = Array.new
x.push("Fail Count")
cnt = read_oneline_file(myfile(name,"failcnt"))
failcnt = cnt.to_s
if (@memsw) then
cnt = read_oneline_file(myfile(name, "memsw.failcnt"))
failcnt="#{failcnt} (#{cnt.to_s})"
end
x.push(failcnt)
data.push(x)
begin
f = File.open(myfile(name,"stat"), "r")
for x in ["Cache","Rss","Pagein","Pageout",nil, nil, nil, nil, nil,
"HierarchyLimit","SubtreeCache","SubtreeRss", nil, nil,
nil, nil, nil, nil, nil, nil, "soft_limit_prio"]
line =f.readline
next if x == nil
line =~ /^\S+\s+(.+)/
val=$1
case x
when "Cache","Rss","SubtreeCache","SubtreeRss"
bytes = convert_bytes(val.to_i, 1)
data.push([x, bytes])
when "Pagein","Pageout"
data.push([x, val])
when "soft_limit_prio"
data.push([x, val])
when "HierarchyLimit"
memlimit = convert_bytes(val.to_i, 0)
if (@memsw) then
line =f.readline
line =~ /^\S+\s+(.+)/
memswlimit = convert_bytes(val.to_i, 0)
memlimit += " (" + memswlimit + ")"
end
data.push([x, memlimit])
end
end
ensure
f.close if f != nil
end
true
end
return data if success==true
return nil
end
end
#
# Read /proc/mounts and parse each lines.
# When cgroup mount point is found, each subsystem's cgroups are added
# to subsystem's Hash.
#
def register_subsys(name, mount, option)
if $allsubsys[name] == nil then
subsys = nil
case name
when "cpu" then subsys = Cpu_Subsys.new(mount, option)
when "cpuacct" then subsys = Cpuacct_Subsys.new(mount, option)
when "memory" then subsys = Memory_Subsys.new(mount, option)
when "cpuset" then subsys = Cpuset_Subsys.new(mount, option)
end
if subsys != nil then
$subsys_array.push(name)
$allsubsys[name] = subsys
end
end
end
#
# Read /proc/mounts and prepare subsys array
#
def parse_mount(line)
parsed = line.split(/\s+/)
if parsed[2] == "cgroup" then
mount=parsed[1]
opts=parsed[3].split(/\,/)
opts.each do |name|
case name
when "rw" then next
else
register_subsys(name, mount, parsed[3])
$allmounts[mount]=name
end
end
end
end
def read_mount
File.open("/proc/mounts", "r") do |file|
file.each_line {|line| parse_mount(line) }
end
$subsys_array.sort!
end
#
# Read all /proc/mounts and scan directory under mount point.
#
def refresh_all
$allmounts.clear
$subsys_array.clear
$allsubsys.clear
read_mount
end
def check_and_refresh_mount_info
mysubsys=Array.new
File.open("/proc/mounts", "r") do |file|
file.each_line do |line|
parsed = line.split(/\s+/)
if (parsed[2] == "cgroup") then
mysubsys.push(parsed[1])
end
end
end
if (mysubsys.size != $allmounts.size) then
refresh_all
return true
end
mysubsys.each do |x|
if ($allmounts[x] == nil) then
refresh_all
return true
end
end
return false
end
[-- Attachment #4: ctop.rb --]
[-- Type: application/octet-stream, Size: 20106 bytes --]
#
# ctop.rb
# written by KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
# Copyright 2009 Fujitsu Limited
#
# Changelog:
#
# v003
# - fixed bug in rmdir/mkdir
# - changed command-mode interface
# - added comments and made codes clean
#
# v002 (2009/02/25)
# - fixed leak of file descriptor
# - mount/umount <-> reload data problem is fixed.
# - "mount twice" problem is fixed.
# - removed R key for reload all. it's now automatic
# - handle "noprefix" mount option
# - show mount option in help window
# - add cpuset support
# - add command-mode
#
# v001 (2009/02/04)
# - first version released
# - cpu, cpuacct, memory subsys is supported
# known bugs -> noprefix, umount, mount twice
#
require 'cgroup.rb'
require 'curses'
require 'etc'
require 'timeout'
require 'singleton'
DIRWIN_LINES=7
DIRWIN_FIELDS= DIRWIN_LINES - 2
UPKEY=256
DOWNKEY=257
RIGHTKEY=258
LEFTKEY=259
#mode
SHOWMOUNT=0
SHOWTASKS=1
SHOWSUBSYS=2
#for 'ps'
PID=0
STATE=1
PPID=2
UID=3
COMMAND=4
PGID=5
#for process status filter
RUNNING=0
#
# Helper function for curses
#
def hit_any_key(str, window)
window.addstr(str) if str != nil
window.addstr("\n[Hit Any Key]")
window.getch
end
def window_printf(window, format, *arg)
str = sprintf(format, *arg)
window.addstr(str)
end
#
# Cursor holds current status of subsys's window.
#
#
class Cursor
def initialize(name)
@subsysname=name # name of subsys
@cursor=0 # current directroy position
@mode=SHOWTASKS # current mode (ps-mode/stat-mode)
@info_startline=0 # used for scroll in infowin
@info_endline=0 # used for scorll in infowin
@show_only_running = 0 # a filter for ps-mode
@user_name_filter=nil # a filter for ps-mode
@command_name_filter=nil # a filter for ps-mode
end
def pos
@cursor
end
def mode
@mode
end
def change_mode # switch mode ps-mode <-> stat-mode
case @mode
when SHOWTASKS then @mode=SHOWSUBSYS
when SHOWSUBSYS then @mode=SHOWTASKS
end
end
#
# Filter for PS-MODE
#
def process_status_filter(stat)
return true if (@show_only_running == 0)
return true if (stat =="R")
return false
end
def user_name_filter(str)
return true if (@user_name_filter == nil)
return true if (@user_name_filter == str)
return false
end
def command_name_filter(str)
return true if (@command_name_filter == nil)
return true if (str =~ /#{@command_name_filter}/)
return false
end
def toggle_show_only_running
if (@show_only_running == 0) then
@show_only_running = 1 # show only running process in ps-mode
else
@show_only_running = 0 # show all processes
end
end
def set_user_name_filter(str)
str = nil if (str == "")
@user_name_filter=str
end
def set_command_name_filter(str)
str=nil if (str == "")
@command_name_filter=str
end
#
# Scroll management for infowin
#
def info_startline
@info_startline
end
def set_infoendline(num)
@info_endline=num
end
def set_infoline(num)
if ((num < 0) || (num >= @info_endline)) then
@info_startline=0
else
@info_startline=num
end
end
#
# chdir() for subsys.
#
def move(direction)
subsys =$allsubsys[@subsysname]
if (subsys == nil) then return
end
if (direction == -1) then
@cursor -= 1 if @cursor > 0
elsif (direction == 1)
@cursor += 1 if @cursor < subsys.size-1
end
end
end
#
# Current is a singleton holds current status of this program.
#
class Current
include Singleton
def initialize
@index=-1 #current susbsys index in $subsys_array[]
@name=nil #current name of subsys
@cursor=nil #reference to current Cursor
@subsys=nil #reference to current Subsys
@subsys_cursor = Hash.new
end
def set(x)
@index=x
if (x == -1) then
@index, @name, @cursor, @subsys = -1, "help", nil, nil
else
@name = $subsys_array[x]
@subsys = $allsubsys[@name]
if (@subsys_cursor[@name] == nil) then
@subsys_cursor[@name] = Cursor.new(@name)
end
@cursor = @subsys_cursor[@name]
end
end
#change subsys view
def move (dir)
case dir
when "left"
@index -= 1 if (@index > -1)
when "right"
@index += 1 if (@index < $subsys_array.size - 1)
end
set(@index)
end
#change directroy view of current cursor
def chdir(direction)
if (@cursor != nil) then
@cursor.move(direction)
end
end
#switch current mode of cursor
def change_mode
if (@cursor != nil) then
@cursor.change_mode
end
end
def name
@name
end
def cursor
@cursor
end
def subsys
@subsys
end
end
$cur = Current.instance
#
# Show directory window
#
def detect_dirlist_position(subsysname, subsys)
pos = 0
size=subsys.size
cursor = $cur.cursor
return [0, 0, 0] if cursor == nil
pos = cursor.pos
if ((size < 4) || (pos <= 2)) then
head=0
tail=4
elsif (pos < size - 2) then
head=pos-1
tail=pos+2
else
head = size - 4
tail = size - 1
end
return [pos, head, tail]
end
def get_owner_name(name)
begin
stat = File.stat(name)
rescue
return ""
end
begin
info = Etc::getpwuid(stat.uid)
uname = info.name
rescue
$barwin.addstr($!)
uname = stat.uid.to_s
end
begin
info = Etc::getgrgid(stat.gid)
gname = info.name
rescue
gname = stat.gid.to_s
end
sprintf("\t-\t(%s/%s)", uname, gname)
end
def draw_dirlist(dirwin, subsys)
now, head, tail = detect_dirlist_position($cur.name, subsys)
lines=1
i=head
while i <= tail
name = subsys.ent(i)
if (name == nil) then break
end
dirwin.setpos(lines, 3)
dirwin.standout if (i == now)
dirwin.addstr(name + get_owner_name(name))
dirwin.standend if (i == now)
lines+=1
i += 1
end
end
#
# Fill dirwin contents.
#
def draw_dirwin(dirwin)
dirwin.clear
dirwin.box(?|,?-,?*)
dirwin.setpos(0, 1)
#show all subsyss in head
-1.upto($subsys_array.size) do |x|
dirwin.addstr("-")
if (x == -1) then
str="help"
else
str=sprintf("%s",$subsys_array[x])
end
break if (str == nil)
dirwin.standout if (str == $cur.name)
dirwin.addstr(str)
dirwin.standend if (str == $cur.name)
end
#show current time
dirwin.setpos(6,dirwin.maxx-32)
dirwin.addstr("[#{Time.now.asctime}]")
#
# Show directory list
#
if $cur.subsys != nil then
#Reload information
$cur.subsys.reload
draw_dirlist(dirwin, $cur.subsys)
end
end
#
#
# for infowin
#
#
# Contents of infowin will be passed by data[]
# This function shows contents based on current scroll infromation.
# for converting contents of array to string, code block is called by yield
#
def draw_infowin_limited(infowin, cursor, data)
#
# Generate Header
#
str = yield nil # write a header if necessary
if (str != nil) then
draw=1
infowin.setpos(0,2)
infowin.addstr(str)
else
draw=0
end
#
# print a line whici is in the window
#
startline = cursor.info_startline
endline = cursor.info_startline + infowin.maxy-2
startline.upto(endline) do |linenumber|
x = data.at(linenumber)
return if (x == nil) #no more data
str = yield(x)
infowin.setpos(draw, 2)
infowin.addstr(str)
draw = 1+infowin.cury
break if (draw == infowin.maxy)
end
cursor.set_infoendline(data.size)
end
#
#
# Show help and current mount information in help window
#
def show_mount_info(infowin)
if ($allsubsys.empty?) then
$barwin.addstr("cgroups are not mounted\n")
end
$allsubsys.each do |name, subsys|
window_printf(infowin, "%12s\t%s\t#%s\n",
name, subsys.mount_point, subsys.option)
end
#$barwin.addstr("mounted subsystems")
#
# Help
#
infowin.addstr("Command\n")
infowin.addstr("[LEFT, RIGHT]\t move subsystems\n")
infowin.addstr("[UP, DOWN]\t move directory\n")
infowin.addstr("[n, b]\t\t scorll information window\n")
infowin.addstr("[s]\t\t switch shown information (ps-mode/stat-mode)\n")
infowin.addstr("[r]\t\t set refresh rate\n")
infowin.addstr("[c]\t\t Enter command-mode\n")
infowin.addstr("ps mode option\n")
infowin.addstr("[t]\t\t (ps-mode)toggle show only running process\n")
infowin.addstr("[u]\t\t (ps-mode)set/unset user name filter\n")
infowin.addstr("[f]\t\t (ps-mode)set/unset command name filter")
end
#
# Read /proc/<pid>/status file and fill data[] array, return it
#
def parse_pid_status(f, es)
input = f.readline
input =~ es
return $1
end
#
# data[] =[PID, State, PPID, UID, COMMAND, PGID]
#
def parse_process(pid)
#
# Status
#
data = Array.new
stat = nil
stat = catch(:bad_task_status) do
data[PID]=pid.to_i
begin
f = File.open("/proc/#{pid}/status", "r")
#Name
data[COMMAND] = parse_pid_status(f,/^Name:\s+(.+)/)
unless (File.exist?("/proc/#{pid}/exe")) then
data[COMMAND] = "[" + data[COMMAND] + "]"
end
#State
data[STATE] = parse_pid_status(f, /^State:\s+([A-Z]).+/)
# TGID: Is thread grouo leader ?
if (parse_pid_status(f, /^Tgid:\s+(.+)/) != pid) then
throw :bad_task_status, false
end
#skip PID
input = f.readline
#PPID
data[PPID]= parse_pid_status(f,/^PPid:\s+(.+)/)
ppid=data[PPID]
#TracerPID
input = f.readline
#UID
uid = parse_pid_status(f,/^Uid:\s+([0-9]+).+/)
begin
info=Etc::getpwuid(uid.to_i)
data[UID]=info.name
rescue
data[UID]=uid
end
rescue
throw :bad_task_status, false
ensure
f.close unless f.nil?
end
end
return data unless stat.nil?
return nil
end
#
# PS-MODE
# Cat "tasks" file and visit all /proc/<pid>/status file
# All information will be pushed into "ps" array
#
def show_tasks(subsys, cursor, infowin)
# Get Name of Current Cgroup and read task file
ps = Array.new
catch :quit do
group = subsys.ent(cursor.pos)
throw :quit,"nogroup" if group==nil
tasks = subsys.tasks(group)
throw :quit,"nogroup" if tasks==nil
tasks.each do |x|
data = parse_process(x)
next if (data == nil)
next unless (cursor.process_status_filter(data[STATE]))
next unless (cursor.command_name_filter(data[COMMAND]))
ps.push(data) if (cursor.user_name_filter(data[UID]))
end
#
# Sort ps's result, "R" first.
#
ps.sort! do |x , y|
if (x[STATE] == "R" && y[STATE] != "R") then
-1
elsif (x[STATE] != "R" && y[STATE] == "R") then
1
else
0
end
end
end
return if (ps.size == 0)
draw_infowin_limited(infowin, cursor, ps)do |x|
if (x == nil) then
sprintf("%6s %6s %8s %5s %16s", "PID","PPID","USER","STATE", "COMMAND")
else
sprintf("%6d %6d %8s %5s %16s",
x[PID], x[PPID], x[UID], x[STATE], x[COMMAND])
end
end
unless ($cur.cursor.process_status_filter("S")) then
$barwin.addstr("[r]")
end
unless ($cur.cursor.user_name_filter("badnamemandab")) then
$barwin.addstr("[u]")
end
unless ($cur.cursor.command_name_filter("badnamemandab")) then
$barwin.addstr("[c]")
end
end
def show_subsys_stat(subsys, cursor, infowin)
group = subsys.ent(cursor.pos)
return if group == nil
data = subsys.stat(group)
return if data == nil
draw_infowin_limited(infowin, cursor, data) do |x|
next if x == nil
if (x[0].size > 24) then
len = x[0].size - 24
x[0].slice!(0..len)
end
sprintf("%24s\t%s", x[0], x[1])
end
end
#
# [n],[b] Move cursor's current position in infowin
#
def set_scroll(infowin, direction)
cursor = $cur.cursor
return if (cursor == nil)
if (direction == 1) then
curline=cursor.info_startline
cursor.set_infoline(curline+infowin.maxy)
else
curline=cursor.info_startline
cursor.set_infoline(curline-infowin.maxy)
end
end
#
# [t] Set/Unset Show-Running-Only filter
#
def toggle_running_filter
if ($cur.cursor != nil) then
$cur.cursor.toggle_show_only_running
end
end
#
# Filters for ps-mode
#
#
# [u] Filter by UID
#
def user_name_filter(infowin)
infowin.clear
window_printf(infowin, "user name filter:")
str=infowin.getstr
cursor= $cur.cursor
cursor.set_user_name_filter(str) if (cursor != nil)
end
#
# [f] Filter by name of command
#
def command_name_filter(infowin)
infowin.clear
window_printf(infowin, "command name filter:")
str=infowin.getstr
cursor =$cur.cursor
cursor.set_command_name_filter(str) if (cursor != nil)
end
#
# [r] set refresh time
#
def set_refresh_time(time, infowin)
infowin.clear
window_printf(infowin, "set refresh time(now %ds)",time)
str=infowin.getstr
return time if (str.to_i == 0)
return str.to_i
end
#
# [c] Below are sub routines for command-mode.
#
def smart_print(str, window)
if (window.maxx - window.curx < str.size-2) then
window.addstr("\n"+str)
else
window.addstr(str)
end
end
def show_writable_files(subsys, cursor, infowin)
group = subsys.ent(cursor.pos)
return nil if group == nil
ent=1
data = Array.new
subsys.each_writable_files(group) do |x|
str = sprintf("%2d: %s ", ent, File.basename(x))
ent=ent+1
smart_print(str, infowin)
data.push(x)
end
infowin.refresh
return data
end
#
# Scan directroy and change owner/group of all regular files
# and current directory.
#
def chown_all_files(uid, gid, group, infowin)
# change owner/group of current dir
begin
File.chown(uid, gid, group)
rescue
hit_any_key("Error:"+$!, infowin)
return
end
# change owner/group of regular files
Dir.foreach(group) do |x|
name = group+"/"+x
next if File.directory?(name)
begin
File.chown(nil, gid, name)
rescue
hit_any_key("Error:"+$!, infowin)
break
end
end
end
#
# Check "/" is included or not at mkdir/rmdir
#
def check_mkrmdir_string(str, infowin)
if (str =~ /\//) then
infowin.addstr("don't include /\n")
return false
elsif (str == ".") then
infowin.addstr("can't remove current\n")
end
return true
end
#
# Get string and retuns uid or gid as integer
#
def parse_id(window, uid, str)
if (str =~ /\D/) then
begin
if (uid == 1) then
info = Etc::getpwnam(str)
id = info.uid
else
info = Etc::getgrnam(str)
id = info.gid
end
rescue
hit_any_key("Error:"+$!, window)
id=nil
end
else
id = str.to_i
end
return id
end
#
#
# Command mode interface
#
#
def command_mode(infowin)
return if ($cur.subsys == nil)
infowin.clear
$barwin.clear
$barwin.addstr("[command-mode]")
$barwin.refresh
#
# Subsys special files are in number
#
infowin.addstr("====subsys command====\n")
data = show_writable_files($cur.subsys, $cur.cursor, infowin)
if data==nil then
infowin.addstr("no subsys command")
end
#
# Cgroup generic ops are in alphabet
#
infowin.addstr("\n====cgroup command====\n")
smart_print("[A] attach task(PID)", infowin)
smart_print(" [M] mkdir", infowin)
smart_print(" [R] rmdir",infowin)
smart_print(" [O] chown(OWNER)", infowin)
smart_print(" [G] chown(GID)", infowin)
infowin.addstr("\n\nModify which ? [and Hit return]:")
#line to show prompt
endline = infowin.cury+1
#wait for the numbers or AOGMR
str=infowin.getstr
#target directory is this.
group = $cur.subsys.ent($cur.cursor.pos)
case str.to_i # if str is not number, returns 0.
# Subsystem commands
when 1..99
if (data != nil) then
name = data.at(str.to_i - 1)
#get input
infowin.setpos(endline, 0)
window_printf(infowin, "#echo to >%s:", File.basename(name))
str = infowin.getstr
#write
begin
f = File.open(name, "w") {|f| f.write(str) }
rescue
hit_any_key("Error:"+$!, infowin)
end
end
# Cgroup commands (str.to_i returns 0)
when 0
case str
when "a","A" #Attach
window_printf(infowin, "Attach task to %s:", group)
str = infowin.getstr
begin
File.open(group + "/tasks", "w") {|f| f.write(str) }
rescue
hit_any_key("Error:"+$!, infowin)
end
when "o","O" #chown (OWNER)
infowin.addstr("change owner id of all files to:")
id = parse_id(infowin, 1, infowin.getstr)
chown_all_files(id, -1, group, infowin) if id != nil
when "g","G" #chown (GROUP)
infowin.addstr("change group id of all files to:")
id = parse_id(infowin, 0, infowin.getstr)
chown_all_files(-1, id, group, infowin) if id != nil
when "m","M" #mkdir
infowin.addstr("mkdir -.enter name:")
str = infowin.getstr
if (check_mkrmdir_string(str, infowin)) then
begin
if (Dir.mkdir(group+"/"+str) != 0) then
hit_any_key("Error:"+$!, infowin)
end
rescue
hit_any_key("Error:"+$!, infowin)
end
else
hit_any_key(nil, infowin)
end
when "r","R" #rmdir
infowin.addstr("rmdir -.enter name:")
str = infowin.getstr
if (check_mkrmdir_string(str, infowin)) then
begin
if (Dir.rmdir(group+"/"+str) != 0) then
hit_any_key("Error:"+$!, infowin)
end
rescue
hit_any_key("Error:"+$!, infowin)
end
else
hit_any_key(nil, infowin)
end
end
end
$barwin.clear
end
#
# Main draw routine
#
def draw_infowin(infowin)
infowin.clear
cursor = $cur.cursor
if cursor == nil then
mode = SHOWMOUNT
else
mode = cursor.mode
end
#
# If no subsys is specified, just show mount information.
#
case mode
when SHOWMOUNT
show_mount_info(infowin)
when SHOWTASKS
$barwin.addstr("[ps-mode]")
show_tasks($cur.subsys, cursor, infowin)
when SHOWSUBSYS
$barwin.addstr("[stat-mode]")
show_subsys_stat($cur.subsys, cursor, infowin)
end
end
#
# Main loop
#
#
# For stdscreen
#
# Check /proc/mounts and read all subsys.
#
refresh_all
#
# Main loop. create windows and wait for inputs
#
Curses::init_screen
begin
$lines=Curses::lines
$cols=Curses::cols
off=0
#
# Create window
#
dirwin = Curses::stdscr.subwin(DIRWIN_LINES, $cols, off, 0)
#for misc info
off+=DIRWIN_LINES
$barwin = Curses::stdscr.subwin(1, $cols, off, 0);
$barwin.standout
off+=1
infowin = Curses::stdscr.subwin($lines-off, $cols, off, 0)
mode=SHOWTASKS
quit=0
refresh_time=15
while quit == 0
#$barwin.clear
#$barwin.addstr("Info:")
draw_dirwin(dirwin)
draw_infowin(infowin)
dirwin.refresh
infowin.refresh
$barwin.refresh
#
# handle input.
#
$barwin.clear
Curses::setpos(0,0)
ch=0
Curses::noecho
begin
Timeout::timeout(refresh_time) do
ch=Curses::getch
end
rescue Timeout::Error
#$barwin.addstr("timeout")
end
Curses::echo
#check espace sequence
if ch == 27 then
ch = Curses::getch
if ch == 91 then
ch = Curses::getch
case ch
when 65 then ch = UPKEY
when 66 then ch = DOWNKEY
when 67 then ch = RIGHTKEY
when 68 then ch = LEFTKEY
end
end
end
#
#
#
if (check_and_refresh_mount_info) then
$cur.set(-1)
end
#$barwin.addstr(Time.now.asctime)
case ch
when ?q
quit=1
break
when LEFTKEY then $cur.move("left")
when RIGHTKEY then $cur.move("right")
when UPKEY then $cur.chdir(-1)
when DOWNKEY then $cur.chdir(1)
when ?s then $cur.change_mode
when ?n then set_scroll(infowin, 1)
when ?b then set_scroll(infowin, -1)
when ?t then toggle_running_filter
when ?u then user_name_filter(infowin)
when ?f then command_name_filter(infowin)
when ?c then command_mode(infowin)
when ?r then refresh_time=set_refresh_time(refresh_time, infowin)
end
end
ensure
Curses::close_screen
end
next prev parent reply other threads:[~2009-04-03 8:25 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-04-03 8:08 [RFC][PATCH 0/9] memcg soft limit v2 (new design) KAMEZAWA Hiroyuki
2009-04-03 8:09 ` [RFC][PATCH 1/9] " KAMEZAWA Hiroyuki
2009-04-03 8:10 ` [RFC][PATCH 2/9] soft limit framework for memcg KAMEZAWA Hiroyuki
2009-04-03 8:12 ` [RFC][PATCH 3/9] soft limit update filter KAMEZAWA Hiroyuki
2009-04-06 9:43 ` Balbir Singh
2009-04-07 0:04 ` KAMEZAWA Hiroyuki
2009-04-07 2:26 ` Balbir Singh
2009-04-03 8:12 ` [RFC][PATCH 4/9] soft limit queue and priority KAMEZAWA Hiroyuki
2009-04-06 11:05 ` Balbir Singh
2009-04-06 23:55 ` KAMEZAWA Hiroyuki
2009-04-06 18:42 ` Balbir Singh
2009-04-06 23:54 ` KAMEZAWA Hiroyuki
2009-04-03 8:13 ` [RFC][PATCH 5/9] add more hooks and check in lazy manner KAMEZAWA Hiroyuki
2009-04-03 8:14 ` [RFC][PATCH 6/9] active inactive ratio for private KAMEZAWA Hiroyuki
2009-04-03 8:15 ` [RFC][PATCH 7/9] vicitim selection logic KAMEZAWA Hiroyuki
2009-04-03 8:17 ` [RFC][PATCH 8/9] lru reordering KAMEZAWA Hiroyuki
2009-04-03 8:18 ` [RFC][PATCH 9/9] more event filter depend on priority KAMEZAWA Hiroyuki
2009-04-03 8:24 ` KAMEZAWA Hiroyuki [this message]
2009-04-06 9:08 ` [RFC][PATCH 0/9] memcg soft limit v2 (new design) Balbir Singh
2009-04-07 0:16 ` KAMEZAWA Hiroyuki
2009-04-24 12:24 ` Balbir Singh
2009-04-24 15:19 ` KAMEZAWA Hiroyuki
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20090403172453.3a229bb7.kamezawa.hiroyu@jp.fujitsu.com \
--to=kamezawa.hiroyu@jp.fujitsu.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox