On a multicore system, support parralel slices in the batch runner.

master
daid 2012-06-28 15:51:40 +02:00
parent a91261cc7a
commit 3642bc46eb
1 changed files with 68 additions and 43 deletions

View File

@ -1,7 +1,7 @@
from __future__ import absolute_import from __future__ import absolute_import
import __init__ import __init__
import wx, os, platform, types, webbrowser, math, subprocess, threading, time, re import wx, os, platform, types, webbrowser, math, subprocess, multiprocessing, threading, time, re
from util import profile from util import profile
from util import sliceRun from util import sliceRun
@ -93,23 +93,38 @@ class BatchSliceProgressWindow(wx.Frame):
self.filenameList = filenameList self.filenameList = filenameList
self.sliceCmdList = sliceCmdList self.sliceCmdList = sliceCmdList
self.abort = False self.abort = False
self.prevStep = 'start'
self.totalDoneFactor = 0.0
self.startTime = time.time()
self.sliceStartTime = time.time() self.sliceStartTime = time.time()
self.sizer = wx.GridBagSizer(2, 2)
self.statusText = wx.StaticText(self, -1, "Building: %d XXXXXXXXXXXXXXXXXXXXX" % (len(self.sliceCmdList)))
self.progressGauge = wx.Gauge(self, -1)
self.progressGauge.SetRange(10000)
self.progressGauge2 = wx.Gauge(self, -1)
self.progressGauge2.SetRange(len(self.sliceCmdList))
self.abortButton = wx.Button(self, -1, "Abort")
self.sizer.Add(self.statusText, (0,0), span=(1,4))
self.sizer.Add(self.progressGauge, (1, 0), span=(1,4), flag=wx.EXPAND)
self.sizer.Add(self.progressGauge2, (2, 0), span=(1,4), flag=wx.EXPAND)
self.sizer.Add(self.abortButton, (3,0), span=(1,4), flag=wx.ALIGN_CENTER) try:
self.threadCount = multiprocessing.cpu_count() - 1
except:
self.threadCount = 1
if self.threadCount < 1:
self.threadCount = 1
self.cmdIndex = 0
self.prevStep = []
self.totalDoneFactor = []
for i in xrange(0, self.threadCount):
self.prevStep.append('start')
self.totalDoneFactor.append(0.0)
self.sizer = wx.GridBagSizer(2, 2)
self.progressGauge = []
self.statusText = []
for i in xrange(0, self.threadCount):
self.statusText.append(wx.StaticText(self, -1, "Building: %d XXXXXXXXXXXXXXXXXXXXX" % (len(self.sliceCmdList))))
self.progressGauge.append(wx.Gauge(self, -1))
self.progressGauge[i].SetRange(10000)
self.progressGaugeTotal = wx.Gauge(self, -1)
self.progressGaugeTotal.SetRange(len(self.sliceCmdList))
self.abortButton = wx.Button(self, -1, "Abort")
for i in xrange(0, self.threadCount):
self.sizer.Add(self.statusText[i], (i*2,0), span=(1,4))
self.sizer.Add(self.progressGauge[i], (1+i*2, 0), span=(1,4), flag=wx.EXPAND)
self.sizer.Add(self.progressGaugeTotal, (1+self.threadCount*2, 0), span=(1,4), flag=wx.EXPAND)
self.sizer.Add(self.abortButton, (2+self.threadCount*2,0), span=(1,4), flag=wx.ALIGN_CENTER)
self.sizer.AddGrowableCol(0) self.sizer.AddGrowableCol(0)
self.sizer.AddGrowableRow(0) self.sizer.AddGrowableRow(0)
@ -118,7 +133,7 @@ class BatchSliceProgressWindow(wx.Frame):
self.Layout() self.Layout()
self.Fit() self.Fit()
threading.Thread(target=self.OnRun).start() threading.Thread(target=self.OnRunManager).start()
def OnAbort(self, e): def OnAbort(self, e):
if self.abort: if self.abort:
@ -127,20 +142,38 @@ class BatchSliceProgressWindow(wx.Frame):
self.abort = True self.abort = True
self.abortButton.SetLabel('Close') self.abortButton.SetLabel('Close')
def SetProgress(self, stepName, layer, maxLayer): def SetProgress(self, index, stepName, layer, maxLayer):
if self.prevStep != stepName: if self.prevStep[index] != stepName:
self.totalDoneFactor += sliceRun.sliceStepTimeFactor[self.prevStep] self.totalDoneFactor[index] += sliceRun.sliceStepTimeFactor[self.prevStep[index]]
newTime = time.time() newTime = time.time()
#print "#####" + str(newTime-self.startTime) + " " + self.prevStep + " -> " + stepName self.prevStep[index] = stepName
self.startTime = newTime
self.prevStep = stepName
progresValue = ((self.totalDoneFactor + sliceRun.sliceStepTimeFactor[stepName] * layer / maxLayer) / sliceRun.totalRunTimeFactor) * 10000 progresValue = ((self.totalDoneFactor[index] + sliceRun.sliceStepTimeFactor[stepName] * layer / maxLayer) / sliceRun.totalRunTimeFactor) * 10000
self.progressGauge.SetValue(int(progresValue)) self.progressGauge[index].SetValue(int(progresValue))
self.statusText.SetLabel(stepName + " [" + str(layer) + "/" + str(maxLayer) + "]") self.statusText[index].SetLabel(stepName + " [" + str(layer) + "/" + str(maxLayer) + "]")
def OnRun(self): def OnRunManager(self):
for action in self.sliceCmdList: threads = []
for i in xrange(0, self.threadCount):
threads.append(threading.Thread(target=self.OnRun, args=(i,)))
for t in threads:
t.start()
for t in threads:
t.join()
self.abort = True
sliceTime = time.time() - self.sliceStartTime
status = "Build: %d" % (len(self.sliceCmdList))
status += "\nSlicing took: %02d:%02d" % (sliceTime / 60, sliceTime % 60)
wx.CallAfter(self.statusText[0].SetLabel, status)
wx.CallAfter(self.OnSliceDone)
def OnRun(self, index):
while self.cmdIndex < len(self.sliceCmdList):
action = self.sliceCmdList[self.cmdIndex]
self.cmdIndex += 1
wx.CallAfter(self.SetTitle, "Building: [%d/%d]" % (self.sliceCmdList.index(action) + 1, len(self.sliceCmdList))) wx.CallAfter(self.SetTitle, "Building: [%d/%d]" % (self.sliceCmdList.index(action) + 1, len(self.sliceCmdList)))
p = subprocess.Popen(action, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) p = subprocess.Popen(action, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
@ -152,33 +185,25 @@ class BatchSliceProgressWindow(wx.Frame):
progress = line[9:-1].split(":") progress = line[9:-1].split(":")
if len(progress) > 2: if len(progress) > 2:
maxValue = int(progress[2]) maxValue = int(progress[2])
wx.CallAfter(self.SetProgress, progress[0], int(progress[1]), maxValue) wx.CallAfter(self.SetProgress, index, progress[0], int(progress[1]), maxValue)
else: else:
print line print line
wx.CallAfter(self.statusText.SetLabel, line) wx.CallAfter(self.statusText[index].SetLabel, line)
if self.abort: if self.abort:
p.terminate() p.terminate()
wx.CallAfter(self.statusText.SetLabel, "Aborted by user.") wx.CallAfter(self.statusText[index].SetLabel, "Aborted by user.")
return return
line = p.stdout.readline() line = p.stdout.readline()
self.returnCode = p.wait() self.returnCode = p.wait()
wx.CallAfter(self.progressGauge.SetValue, 10000) wx.CallAfter(self.progressGauge[index].SetValue, 10000)
self.totalDoneFactor = 0.0 self.totalDoneFactor[index] = 0.0
wx.CallAfter(self.progressGauge2.SetValue, self.sliceCmdList.index(action) + 1) wx.CallAfter(self.progressGaugeTotal.SetValue, self.cmdIndex)
self.abort = True
sliceTime = time.time() - self.sliceStartTime
status = "Build: %d" % (len(self.sliceCmdList))
status += "\nSlicing took: %02d:%02d" % (sliceTime / 60, sliceTime % 60)
wx.CallAfter(self.statusText.SetLabel, status)
wx.CallAfter(self.OnSliceDone)
def OnSliceDone(self): def OnSliceDone(self):
self.abortButton.Destroy() self.abortButton.Destroy()
self.closeButton = wx.Button(self, -1, "Close") self.closeButton = wx.Button(self, -1, "Close")
self.sizer.Add(self.closeButton, (3,0), span=(1,1)) self.sizer.Add(self.closeButton, (2+self.threadCount*2,0), span=(1,1))
self.Bind(wx.EVT_BUTTON, self.OnAbort, self.closeButton) self.Bind(wx.EVT_BUTTON, self.OnAbort, self.closeButton)
self.Layout() self.Layout()
self.Fit() self.Fit()