ちょっとしたデモに便利かも、ということで作ってみました。
005 と 006 の 2 つのコンテナで無駄ループ(loop005, loop006)を回しています。どちらも CPU Pinning を 1 にセットしているので、CPU1 だけが 100% で振り切れています。ただし、CPU Shares を 2:1 に配分しているので、loop005 と loop006 の CPU 使用率がちょうど 2:1 に配分されています。
LXC の環境は、こちらを使用しています。
今回は LXC コンテナに適用していますが、KVM の仮想マシンに対しても同じことが実現可能です。
ソースコードはこちら。
#!/usr/bin/python import sys, os, re, commands from Tkinter import * from tkMessageBox import * class CpuSet( Frame ): def __init__( self, parent, container, cgroups, **params ): Frame.__init__( self, parent, **params ) self.cont = container self.cgdir = cgroups self.cpunums = int( commands.getoutput( "grep processor /proc/cpuinfo | wc -l" ) ) self.statesVar = [] self.states = [] cpus = commands.getoutput( "cat " + os.path.join( self.cgdir, self.cont, "cpuset.cpus" ) ) self.label = Label( self, text="CPU Pinning / Current: " + cpus ) self.label.pack( side=TOP, anchor=W ) for i in range( self.cpunums ): var = IntVar() chk = Checkbutton( self, text=str( i ), variable=var ) chk.pack( side=LEFT ) self.states.append( 0 ) self.statesVar.append( var ) for item in cpus.split( "," ): match = re.match( r"^(\d+)-(\d+)", item ) if match: for i in range( int(match.group(1)), int(match.group(2)) + 1 ): self.statesVar[ i ].set( 1 ) self.states[ i ] = 1 else: self.statesVar[ int( item ) ].set( 1 ) self.states[ int( item ) ] = 1 def apply( self ): cpus = [] stats = [ self.statesVar[ i ].get() for i in range( self.cpunums ) ] if sum( stats ) == 0: return self.states = stats for i in range( self.cpunums ): if self.states[ i ]: cpus.append( str( i ) ) commands.getoutput( "echo \"" + ",".join( cpus ) + "\" >" + os.path.join( self.cgdir, self.cont, "cpuset.cpus" ) ) cpus = commands.getoutput( "cat " + os.path.join( self.cgdir, self.cont, "cpuset.cpus" ) ) self.label.config( text="CPU Pinning / Current: " + cpus ) def reset( self ): for i in range( self.cpunums ): self.statesVar[ i ].set( self.states[ i ] ) class CpuShares( Frame ): def __init__( self, parent, container, cgroups, **params ): Frame.__init__( self, parent, **params ) self.cont = container self.cgdir = cgroups self.shares = int ( commands.getoutput( "cat " + os.path.join( cgdir, container,"cpu.shares" ) ) ) self.sharesVar = IntVar() self.sharesVar.set( self.shares ) self.cpuscale = Scale( self, variable=self.sharesVar, from_=100, to=2048, length=300, showvalue=YES, orient="horizontal" ) self.label = Label( self, text="CPU Shares / Current: " + str( self.shares ) ) self.label.pack( side=TOP, anchor=W ) self.cpuscale.pack( side=TOP, fill=BOTH, expand=YES ) def apply( self ): self.shares = self.sharesVar.get() commands.getoutput( "echo \"" + str( self.shares ) + "\">" + os.path.join( self.cgdir, self.cont, "cpu.shares" ) ) self.shares = int ( commands.getoutput( "cat " + os.path.join( self.cgdir, self.cont,"cpu.shares" ) ) ) self.label.config( text="CPU Shares / Current: " + str( self.shares ) ) def reset( self ): self.sharesVar.set( self.shares ) class ContainerLabel( Frame ): def __init__( self, parent, container, cgroups, **params ): Frame.__init__( self, parent, **params ) self.cont = container self.cgdir = cgroups self.contlabel = Label( self, text="Container: " + self.cont ) self.contlabel.pack( side=TOP, anchor=W ) class CpuController( Frame ): def __init__( self, parent, container, cgroups, **params ): Frame.__init__( self, parent, **params ) self.cont = container self.cgdir = cgroups contlabel = ContainerLabel( self, self.cont, self.cgdir ) apply = Button( self, text="Apply", command=self.onApply ) reset = Button( self, text="Reset", command=self.onReset ) self.cpuset = CpuSet( self, container, cgroups, bd=1, relief=SUNKEN ) self.cpushares = CpuShares( self, container, cgroups, bd=1, relief=SUNKEN ) self.cpuset.pack( side=TOP, fill=BOTH, expand=YES ) self.cpushares.pack( side=TOP, fill=BOTH, expand=YES ) contlabel.pack( side=LEFT , fill=X, expand=YES ) apply.pack( side=LEFT ) reset.pack( side=LEFT ) def onApply( self ): self.cpushares.apply() self.cpuset.apply() def onReset( self ): self.cpushares.reset() self.cpuset.reset() class MainController: def __init__( self, parent, **params ): self.parent = parent self.params = params self.controller = {} for con in params[ "containers" ]: self.controller[ con ] = CpuController( self.parent, con, params[ "cgroups" ], bd=4, relief=RIDGE ) self.controller[ con ].pack( side=TOP, fill=BOTH, expand=YES ) def getCgroupDir(): for line in open( "/etc/mtab", "r" ): match = re.match( r"^\s*\S+\s+(\S+)\s+cgroup\s+", line ) if match: return match.group(1) return None def getActiveContainers( cgdir ): return filter( lambda f: os.path.isdir( os.path.join( cgdir, f ) ), os.listdir( cgdir ) ) if __name__ == "__main__": cgdir = getCgroupDir() if cgdir == None: print "No cgroup directory in /etc/mtab." exit( 1 ) conts = getActiveContainers( cgdir ) conts.sort() root = Tk() controller = MainController( root, containers=conts, cgroups=cgdir ) root.mainloop() # vi:ts=4