Skip to content

Instantly share code, notes, and snippets.

@ElGuillermo
Forked from zolople/BoinColaBHG.py
Last active April 28, 2024 17:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ElGuillermo/6b2588ef05a64809e3d5e4525b4e17f1 to your computer and use it in GitHub Desktop.
Save ElGuillermo/6b2588ef05a64809e3d5e4525b4e17f1 to your computer and use it in GitHub Desktop.
Boinc on Google Colab with Google Drive
#@title Menu "Affichage" -> "Afficher/masquer le code"
# -----------------------------------------------------------------
App1 = "BoinColaBHG++ for AF"
App2 = "v.22.02.05.wip (see inner code for details)"
Separator = "-----------------------------------------------------------------"
# By : https://github.com/ElGuillermo
# Based on : BoinColaBHG v.21.02.26.015 "Ononis minutissima"
# Author : Bartomeu Homar Graxell
# Web : http://www.zolople.com
# Download : https://gist.github.com/zolople/c96d9759d2b10c0ed126dd0a61901e2d
# Licence : Attribution-NonCommercial-ShareAlike 4.0 International
# https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en
# -----------------------------------------------------------------------------
# Configuration
# -----------------------------------------------------------------------------
# Change the Server's name for each Colab notebook you'll use.
Server = 'Colab01'
# Available languages : 'en', 'fr'
Language = 'fr'
# Interface height (pixels). Default : 500
InterfaceHeight = 400
# Project URL
Projects = {'URLs':['https://wuprop.boinc-af.org/',
'https://sech.me/boinc/Amicable/',
'https://rake.boincfast.ru/rakesearch/',
'https://boinc.progger.info/odlk/',
'http://boincvm.proxyma.ru:30080/test4vm/',
'http://gene.disi.unitn.it/test/',
'https://www.gpugrid.net/',
'https://escatter11.fullerton.edu/nfs/',
'http://numberfields.asu.edu/NumberFields/',
'https://boinc.multi-pool.info/latinsquares/',
'http://milkyway.cs.rpi.edu/milkyway/',
'https://boinc.thesonntags.com/collatz/',
'http://www.worldcommunitygrid.org/',
'http://boincvm.proxyma.ru:30080/test4vm/',
'http://einstein.phys.uwm.edu/'
],
# Your *personal* account keys - give access to your accounts - DO NOT SHARE !
'AUTH':['xxx',
'xxx',
'xxx',
'xxx',
'xxx',
'xxx',
'xxx',
'xxx',
'xxx',
'xxx',
'xxx',
'xxx',
'xxx',
'xxx',
'xxx'
],
# Attach this project ?
'Attach':[True, # wuprop@home
False, # Amicable
False, # Rakeserach
False, # Odlk
False, # PrivateGFN
False, # TNGrid
False, # GPUGrid
False, # NFS
False, # NumberFields
False, # Odlk1
False, # Milkyway
False, # Collatz
False, # World community grid
False, # Private GFN Server
True # Einstein@home
]}
# Default RPC password (leave blank if you do not intend remote controlling)
RPC_Password = ''
# Default cc_config.xml
# Will be stored on your Google drive (but won't overwrite any existent one)
# doc : https://boinc.berkeley.edu/wiki/Client_configuration
UserCCConfig = ("<cc_config>\n\
\t<log_flags>\n\
\t\t<task>0</task>\n\
\t\t<file_xfer>0</file_xfer>\n\
\t\t<sched_ops>1</sched_ops>\n\
\t\t<rr_simulation>0</rr_simulation>\n\
\t\t<unparsed_xml>1</unparsed_xml>\n\
\t</log_flags>\n\
\t<options>\n\
\t\t<abort_jobs_on_exit>0</abort_jobs_on_exit>\n\
\t\t<allow_multiple_clients>0</allow_multiple_clients>\n\
\t\t<max_file_xfers_per_project>20</max_file_xfers_per_project>\n\
\t\t<max_file_xfers>30</max_file_xfers>\n\
\t\t<max_tasks_reported>1000</max_tasks_reported>\n\
\t\t<ncpus>-1</ncpus>\n\
\t\t<process_priority>5</process_priority>\n\
\t\t<process_priority_special>5</process_priority_special>\n\
\t\t<report_results_immediately>1</report_results_immediately>\n\
\t\t<use_all_gpus>1</use_all_gpus>\n\
\t</options>\n\
</cc_config>")
# Default global_prefs_override.xml
# Will be stored on your Google drive (but won't overwrite any existent one)
# doc : https://boinc.berkeley.edu/wiki/Global_prefs_override.xml
UserGlobalPrefsOverride = ("<global_preferences>\n\
\t<cpu_scheduling_period_minutes>5.000000</cpu_scheduling_period_minutes>\n\
\t<cpu_usage_limit>100</cpu_usage_limit>\n\
\t<disk_max_used_pct>95</disk_max_used_pct>\n\
\t<ram_max_used_busy_pct>95</ram_max_used_busy_pct>\n\
\t<ram_max_used_idle_pct>95</ram_max_used_idle_pct>\n\
\t<run_if_user_active/>\n\
\t<run_on_batteries/>\n\
\t<suspend_cpu_usage>100</suspend_cpu_usage>\n\
\t<vm_max_used_pct>95</vm_max_used_pct>\n\
\t<work_buf_min_days>0.02</work_buf_min_days>\n\
\t<work_buf_additional_days>0</work_buf_additional_days>\n\
</global_preferences>")
# Configuration : end
# -----------------------------------------------------------------------------
# Information FR
# -----------------------------------------------------------------------------
#
# - N'essayez pas d'utiliser deux comptes Google différents
# sur le même Google Drive : les drives liés aux deux comptes seraient
# utilisés et leurs fichiers partagés entre les comptes.
#
# - Pour éviter d'avoir à confirmer l'accès à Google Drive
# lors de chaque démarrage : cliquez sur l'icône "Activer Drive"
# dans le volet de gauche, dans la partie "dossiers".
#
# - Lors de l'ajout d'un projet, il est recommandé d'arrêter le notebook
# (option 0) et de le redémarrer. Ceci est nécessaire pour accorder la
# permission de s'exécuter aux nouveaux programmes.
#
# - Les UTs terminées et renvoyées sont supprimées de Google Drive.
# Elles sont envoyées dans la corbeille, dont le volume compte
# pour le quota. Si un projet semble ne plus télécharger d'UTs,
# vérifiez qu'il reste de l'espace disque disponible sur Google Drive.
# Le script vous alertera lorsque 66% d'espace disque seront occupés,
# afin que vous vidiez la corbeille.
# Notez que le vidage peut prendre un certain temps.
# -----------------------------------------------------------------------------
# Python libraries import
# -----------------------------------------------------------------------------
import os
import re
import time
import shutil
from google.colab import widgets
from google.colab import output
from google.colab import drive
from IPython.display import clear_output
from IPython.display import HTML
from IPython import get_ipython
import ipywidgets
# -----------------------------------------------------------------------------
# Constants
# -----------------------------------------------------------------------------
InitialInfo = {
'en':{
'Installing':'Updating Notebook, installing Boinc',
'KillPreviousBoinc':'Kill previous Boinc clients (if any)',
'LaunchBoinc':'Launch and set Boinc client',
'AutoAttachProjects':'Attach projects',
'AutoDetachProjects':'Detach projects',
'StartSequenceEnd':'Waiting for Boinc start sequence\'s end',
},
'fr':{
'Installing':'Mise à jour du Notebook et installation de Boinc',
'KillPreviousBoinc':'Arrêt des précédents clients Boinc (s\'il y en a)',
'LaunchBoinc':'Lancement et configuration du client Boinc',
'AutoAttachProjects':'Rattachement aux projets',
'AutoDetachProjects':'Détachement des projets',
'StartSequenceEnd':'Attente de la fin du démarrage de Boinc',
}
}
menu_buttons = {
'en':{
'MenuBoinc':'Boinc Client',
'MenuProjects':'Projects',
'MenuTasks':'Tasks',
'MenuSystem':'System infos',
'SubBoinc_messages':'Messages',
'SubBoinc_getccstatus':'CPU/GPU/Net usage policies',
'SubBoinc_filetransfers':'File transfers',
'SubBoinc_timestats':'Time stats',
'SubBoinc_readcfg':'Re-read cfg',
'SubBoinc_quit':'Stop Boinc',
'SubBoinc_start':'Start Boinc',
'SubProjects_attached':'Attached',
'SubProjects_apps':'Apps',
'SubProjects_appversions':'Apps versions',
'SubProjects_workunits':'Workunits',
'SubProjects_updateall':'Update all projects',
'SubProjects_operations':'Operations',
'SubProjects_suspend':'Suspend',
'SubProjects_resume':'Resume',
'SubProjects_nomorewus':'No more WUs',
'SubProjects_morewus':'Send WUs',
'SubProjects_update':'Update',
'SubProjects_reset':'Reset',
'SubTasks_running':'Running',
'SubTasks_upload':'Upload',
'SubTasks_error':'Error',
'SubTasks_aborted':'Aborted',
'SubSystem_hostinfo':'Boinc host_info',
'SubSystem_CPU':'CPU : \"top\"',
'SubSystem_GPU':'GPU : \"nvidia-smi\"'
},
'fr':{
'MenuBoinc':'Client Boinc',
'MenuProjects':'Projets',
'MenuTasks':'Tâches',
'MenuSystem':'Infos système',
'SubBoinc_messages':'Messages',
'SubBoinc_getccstatus':'Règles d\'usage CPU/GPU/Net',
'SubBoinc_filetransfers':'Transferts',
'SubBoinc_timestats':'Time stats',
'SubBoinc_readcfg':'Relire cfg',
'SubBoinc_quit':'Arrêter Boinc',
'SubBoinc_start':'Démarrer Boinc',
'SubProjects_attached':'Attachés',
'SubProjects_apps':'Apps',
'SubProjects_appversions':'Apps versions',
'SubProjects_workunits':'UTs',
'SubProjects_updateall':'Màj des projets',
'SubProjects_operations':'Opérations',
'SubProjects_suspend':'Suspendre',
'SubProjects_resume':'Reprendre',
'SubProjects_nomorewus':'Ne plus demander d\'UTs',
'SubProjects_morewus':'Redemander des UTs',
'SubProjects_update':'Mise à jour',
'SubProjects_reset':'Réinitialiser',
'SubTasks_running':'En cours',
'SubTasks_upload':'Envoi',
'SubTasks_error':'Erreur',
'SubTasks_aborted':'Abandonnées',
'SubSystem_hostinfo':'Boinc host_info',
'SubSystem_CPU':'CPU : \"top\"',
'SubSystem_GPU':'GPU : \"nvidia-smi\"'
}
}
WUStates = {'SearchString':['state: upload', 'state: compute error',
'state: aborted', 'active_task_state: EXECUTING'],
'en':[' [upload]', ' [error]', ' [aborted]', ' [__%]'],
'fr':[' [envoi]', ' [erreur]', ' [interrompu]', ' [__%]']
}
OtherMsgs = {'en':{
'TrashBin':'Please, empty the '
+ '<a href="https://drive.google.com/drive/u/0/trash"'
+ ' target="_blank">trashbin</a> of '
},
'fr':{
'TrashBin':'Veuillez vider la '
+ '<a href="https://drive.google.com/drive/u/0/trash"'
+ ' target="_blank">corbeille</a> de '
}
}
# -----------------------------------------------------------------------------
# Functions
# -----------------------------------------------------------------------------
#------------------------------
# Function: title
#------------------------------
def Title(text = "", alignment = "left"):
display(HTML(
'<h3 style="text-align: ' + alignment + ';">' + text + '</h3>'))
#------------------------------
# Function: progress
#------------------------------
def progress(Cuenta, Pasos = 100, Ancho = 100, SegDesde = 0, SegHasta = 1):
"""Shows a time progress bar
Cuenta : posición del cursor de progreso
Pasos : Cantidad de divisiones de tiempo empleadas, normalmente 100
Ancho : pixels de anchura de la barra de progreso
SegDesde, SegHasta: segundos de inicio y final
"""
return HTML("""
{SegDesde}s
<progress
value = '{Cuenta}'
max = '{Pasos}',
style = 'width: {Ancho}px'
>
{Cuenta}
</progress> {Segundos}s / {SegHasta}s
""".format(Segundos = (SegHasta - SegDesde)
* Cuenta/Pasos
+ SegDesde,
Cuenta = Cuenta,
Pasos = Pasos,
SegDesde = SegDesde,
SegHasta = SegHasta,
Ancho = Ancho))
#------------------------------
# Function: wait
#------------------------------
# Wait for a given number of seconds, displaying a progress bar
# depends : function progress()
def wait(InitialSec = 0,
EndSec = 10,
BarWidthpx = 250,
TicksPerSec = 1,
Cumulate = False):
Segundos = EndSec - InitialSec
Pasos = Segundos * TicksPerSec
PasosPrevios = TicksPerSec * InitialSec
if Cumulate:
out = display(
progress(
PasosPrevios,
Pasos + PasosPrevios,
BarWidthpx,
0,
EndSec
),
display_id = True
)
else:
out = display(
progress(
0,
Pasos,
BarWidthpx,
InitialSec,
EndSec
),
display_id = True
)
for ii in range(1, Pasos + 1):
time.sleep((EndSec - InitialSec) / Pasos)
if Cumulate:
out.update(
progress(
ii + PasosPrevios,
Pasos + PasosPrevios,
BarWidthpx,
0,
EndSec
)
)
else:
out.update(
progress(
ii,
Pasos,
BarWidthpx,
InitialSec,
EndSec
)
)
#------------------------------
# Function: Line_ValueY
#------------------------------
def Line_ValueY(X = 50, X0 = 0, Y0 = 0, X1 = 100, Y1 = 100, MaxMin = True):
""" Appelée par la fonction GoogleDriveSpace
Calcule la valeur de Y selon X (X0,Y0) y (X1,Y1).
Si MaxMin == true, Y ne peut sortir des limites [Y0..Y1]
"""
m = (Y1 - Y0) / (X1 - X0) # Pendiente
b = Y0 - m * X0 # intersección
Y = m * X + b
if MaxMin: #aplica márgenes de forma que siempre {Y in [Y0..Y1]}
MaxY = max(Y0, Y1)
MinY = min(Y0, Y1)
Y = max(Y, MinY)
Y = min(Y, MaxY)
return Y
#------------------------------
# Fonction: GoogleDriveSpace
#------------------------------
def GoogleDriveSpace():
"""GoogleDriveSpace().
Affiche le taux de remplissage de Google Drive.
Demande que la corbeille soit vidée à partir de 66%.
"""
GD_Largeur = 100 # width px
GD_debut = 1/3 # green X < 0.33
GD_milieu = 1/2 # yellow 0.33 < X < 0.5
GD_fin = 2/3 # red 0.5 < X < 0.66
# Evaluate free space on Google drive
!df . -h -BM > stdoutdrive.txt
f = open('stdoutdrive.txt','r')
DiskSpace = f.read().splitlines()
f.close()
Spaces = DiskSpace[1][15:].split('M')
Total = float(Spaces[0]) / 1024
Occupied = float(Spaces[1]) / 1024
X = Occupied / Total
# Define
Red = int(Line_ValueY(X, GD_debut, 0, GD_milieu, 255))
Green = int(Line_ValueY(X, GD_milieu, 255, GD_fin, 0))
Color = '#' + format(Red * 65536 + Green * 256, '06x')
if (X > GD_fin): # if occupied > 66%, ask user to empty the recycle bin.
GDMessage = "<b style='color:red;'>" + OtherMsgs[Language]['TrashBin']
else: # if occupied < 66%
GDMessage = "<b>"
display(HTML("""
<div style="display: block; margin: 16px 0 16px 0; text-align:left;">
{GDMessage}Google Drive</b> : {Count}%
<progress
value = '{Count}'
max = '100',
style = 'background-color: {Color}; width: {GD_Largeur}px;'
>
{Count}
</progress> {Occupied} GB / {Total} GB</div>
""".format(Occupied = '{0:.2f}'.format(Occupied),
Total = '{0:.2f}'.format(Total),
Count = int(100 * Occupied / Total),
GD_Largeur = GD_Largeur,
Color = Color,
GDMessage = GDMessage)
)
)
#--------------------------------
# Fonction: GetProjectNameFromURL
#--------------------------------
# Used in stdoutstate_infos() function
def GetProjectNameFromURL(url):
# Using the url to forge an account_*.xml filename
# then opening this file to get <project_name> tag inner data
AccountFile = url.split('://')[1] # gets what's after http(s)://
AccountFile = AccountFile.strip("/") # removes ending slash
AccountFile = AccountFile.replace("/", "_") # replace / for _
AccountFile = 'account_' + AccountFile + '.xml'
if os.path.isfile(
'/content/drive/MyDrive/Boinc/'
+ Server + '/' + AccountFile):
FullPathFilename = ('/content/drive/MyDrive/Boinc/'
+ Server + '/' + AccountFile)
AccountFile_desc = open(FullPathFilename, 'r')
AccountFileContent = AccountFile_desc.read()
AccountFile_desc.close()
ProjectName = (
(AccountFileContent.split('<project_name>')[1])
.split('</project_name>')[0])
else:
ProjectName = '(unknown : no account file found)'
return ProjectName
#--------------------------------
# Fonction: AccountFilesInfos
#--------------------------------
# Gives Project's URL and name for each account_*.xml file found.
# Used in installation : auto attach/auto detach sequence
# Used in function button_action(button)
# Used in function ProjectOperations()
# returns : AccountsFilesInfos[[URL1, name1], [URL2, name2], ...]
# exemple : AccountsFilesInfos[0][0] : "URL1"
# exemple : AccountsFilesInfos[1][0] : "URL2"
# exemple : AccountsFilesInfos[0][1] : "name1"
def AccountFilesInfos():
AccountsFilesInfos = []
for filename in os.listdir('/content/drive/MyDrive/Boinc/' + Server):
if filename.startswith('account_') and filename.endswith('.xml'):
FullPathFilename = ('/content/drive/MyDrive/Boinc/'
+ Server + '/' + filename)
AccountFile_desc = open(FullPathFilename, 'r')
AccountFileContent = AccountFile_desc.read()
AccountFile_desc.close()
MasterURL = (
(AccountFileContent.split('<master_url>')[1])
.split('</master_url>')[0])
ProjectName = (
(AccountFileContent.split('<project_name>')[1])
.split('</project_name>')[0])
ThisAccountFileInfos = [MasterURL, ProjectName]
AccountsFilesInfos.append(ThisAccountFileInfos)
return AccountsFilesInfos
#--------------------------------
# Fonction: button_action
#--------------------------------
def button_action(button):
ProjectsLogsBlocs, ProjectsNames,\
AppsLogsBlocs, AppsNames,\
AppsversionsLogsBlocs, AppsversionsNames,\
WorkunitsLogsBlocs, WorkunitsNames,\
TasksLog, TasksNames,\
Timestats = (stdoutstate_infos())
AccountsFilesInfo = AccountFilesInfos()
# Display command in main interface's header
with RunningScreenOutput.output_to(0, 0):
RunningScreenOutput.clear_cell()
display(HTML('<div style="background-color: #606060;padding: 5px;">'
+ button.description
+ '</div>\n'))
# Main menu
if button.description == menu_buttons[Language]['MenuBoinc']:
with MenuOutput.output_to(1, 0):
MenuOutput.clear_cell()
MenuBoinc.style.button_color = '#808080'
MenuProjects.style.button_color = '#454545'
MenuTasks.style.button_color = '#454545'
MenuSystem.style.button_color = '#454545'
TestBoincRunning = get_ipython().\
getoutput('boinccmd --get_file_transfers').nlstr
isBoincRunning = (
TestBoincRunning != "can't connect to local host"
)
if isBoincRunning:
display(SubBoinc_menu_withquit)
else:
display(SubBoinc_menu_withstart)
# default : first submenu entry displayed
with RunningScreenOutput.output_to(0, 0):
RunningScreenOutput.clear_cell()
display(HTML('<div style="background-color: #606060;'
+ 'padding: 5px;">'
+ menu_buttons[Language]['SubBoinc_messages']
+ '</div>\n'))
with RunningScreenOutput.output_to(2, 0):
RunningScreenOutput.clear_cell()
Messages()
elif button.description == menu_buttons[Language]['MenuProjects']:
with MenuOutput.output_to(1, 0):
MenuOutput.clear_cell()
MenuBoinc.style.button_color = '#454545'
MenuProjects.style.button_color = '#808080'
MenuTasks.style.button_color = '#454545'
MenuSystem.style.button_color = '#454545'
display(SubProjects_menu)
# default : first submenu entry displayed
with RunningScreenOutput.output_to(0, 0):
RunningScreenOutput.clear_cell()
display(HTML('<div style="background-color: #606060;'
+ 'padding: 5px;">'
+ menu_buttons[Language]['SubProjects_attached']
+ '</div>\n'))
with RunningScreenOutput.output_to(2, 0):
RunningScreenOutput.clear_cell()
Attached_infos()
elif button.description == menu_buttons[Language]['MenuTasks']:
with MenuOutput.output_to(1, 0):
MenuOutput.clear_cell()
MenuBoinc.style.button_color = '#454545'
MenuProjects.style.button_color = '#454545'
MenuTasks.style.button_color = '#808080'
MenuSystem.style.button_color = '#454545'
display(SubTasks_menu)
# default : first submenu entry displayed
with RunningScreenOutput.output_to(0, 0):
RunningScreenOutput.clear_cell()
display(HTML('<div style="background-color: #606060;'
+ 'padding: 5px;">'
+ menu_buttons[Language]['SubTasks_running']
+ '</div>\n'))
with RunningScreenOutput.output_to(2, 0):
RunningScreenOutput.clear_cell()
Tasks_infos()
elif button.description == menu_buttons[Language]['MenuSystem']:
with MenuOutput.output_to(1, 0):
MenuOutput.clear_cell()
MenuBoinc.style.button_color = '#454545'
MenuProjects.style.button_color = '#454545'
MenuTasks.style.button_color = '#454545'
MenuSystem.style.button_color = '#808080'
display(SubSystem_menu)
# default : first submenu entry displayed
with RunningScreenOutput.output_to(0, 0):
RunningScreenOutput.clear_cell()
display(HTML('<div style="background-color: #606060;'
+ 'padding: 5px;">'
+ menu_buttons[Language]['SubSystem_hostinfo']
+ '</div>\n'))
with RunningScreenOutput.output_to(2, 0):
RunningScreenOutput.clear_cell()
!boinccmd --get_host_info
# Submenu Boinc
elif button.description == menu_buttons[Language]['SubBoinc_messages']:
with RunningScreenOutput.output_to(2, 0):
RunningScreenOutput.clear_cell()
Messages()
elif button.description == menu_buttons[Language]['SubBoinc_getccstatus']:
with RunningScreenOutput.output_to(2, 0):
RunningScreenOutput.clear_cell()
!boinccmd --get_cc_status
elif button.description == menu_buttons[Language]['SubBoinc_timestats']:
with RunningScreenOutput.output_to(2, 0):
RunningScreenOutput.clear_cell()
func_Timestats()
elif button.description == (
menu_buttons[Language]['SubBoinc_filetransfers']):
with RunningScreenOutput.output_to(2, 0):
RunningScreenOutput.clear_cell()
!boinccmd --get_file_transfers
elif button.description == menu_buttons[Language]['SubBoinc_readcfg']:
with RunningScreenOutput.output_to(2, 0):
RunningScreenOutput.clear_cell()
print('global_prefs_override')
!boinccmd --read_global_prefs_override > /dev/null
print('cc_config')
!boinccmd --read_cc_config > /dev/null
with RunningScreenOutput.output_to(1, 0):
RunningScreenOutput.clear_cell()
wait(0, 5, 250, 1, False)
RunningScreenOutput.clear_cell()
# Displays messages when done
with RunningScreenOutput.output_to(2, 0):
RunningScreenOutput.clear_cell()
Messages()
elif button.description == menu_buttons[Language]['SubBoinc_quit']:
with RunningScreenOutput.output_to(2, 0):
RunningScreenOutput.clear_cell()
print('Bye !')
!boinccmd --quit
with RunningScreenOutput.output_to(1, 0):
RunningScreenOutput.clear_cell()
wait(0, 5, 250, 1, False)
RunningScreenOutput.clear_cell()
elif button.description == menu_buttons[Language]['SubBoinc_start']:
with RunningScreenOutput.output_to(2, 0):
RunningScreenOutput.clear_cell()
print('Let\'s go !')
!boinc --daemon --redirectio --run_cpu_benchmarks\
--start_delay 30 --dir $DataDir
with RunningScreenOutput.output_to(1, 0):
RunningScreenOutput.clear_cell()
wait(0, 5, 250, 1, False)
RunningScreenOutput.clear_cell()
# Submenu Projects
elif button.description == menu_buttons[Language]['SubProjects_attached']:
with RunningScreenOutput.output_to(2, 0):
RunningScreenOutput.clear_cell()
Attached_infos()
elif button.description == menu_buttons[Language]['SubProjects_apps']:
with RunningScreenOutput.output_to(2, 0):
RunningScreenOutput.clear_cell()
Apps_infos()
elif button.description ==\
menu_buttons[Language]['SubProjects_appversions']:
with RunningScreenOutput.output_to(2, 0):
RunningScreenOutput.clear_cell()
Appversions_infos()
elif button.description == menu_buttons[Language]['SubProjects_workunits']:
with RunningScreenOutput.output_to(2, 0):
RunningScreenOutput.clear_cell()
Workunits_infos()
elif button.description == menu_buttons[Language]['SubProjects_updateall']:
with RunningScreenOutput.output_to(2, 0):
RunningScreenOutput.clear_cell()
for i in range(len(Projects['URLs'])):
ProjectURL = repr(Projects['URLs'][i])
if Projects['Attach'][i] == True:
print(ProjectURL)
!boinccmd --project $ProjectURL update > /dev/null
with RunningScreenOutput.output_to(1, 0):
RunningScreenOutput.clear_cell()
wait(0, 5, 250, 1, False)
RunningScreenOutput.clear_cell()
# Displays messages when done
with RunningScreenOutput.output_to(2, 0):
RunningScreenOutput.clear_cell()
Messages()
elif button.description == menu_buttons[Language]\
['SubProjects_operations']:
with RunningScreenOutput.output_to(2, 0):
RunningScreenOutput.clear_cell()
ProjectOperations()
# Projects : operations
elif button.description.find(
menu_buttons[Language]['SubProjects_suspend']) != -1 and\
len(button.description) != (
len(menu_buttons[Language]['SubProjects_suspend'])):
RequiredAction = 'suspend'
ProjectNumber = button.description.rsplit(' ', 1)[1]
for i in range(len(ProjectsNames)):
if AccountsFilesInfo[i][1] == ProjectsNames[int(ProjectNumber)]:
ProjectURL = AccountsFilesInfo[i][0]
with RunningScreenOutput.output_to(0, 0):
RunningScreenOutput.clear_cell()
!boinccmd --project $ProjectURL $RequiredAction
print('(OK) !boinccmd --project '
+ ProjectURL + ' ' + RequiredAction)
wait(0, 5, 250, 1, False)
elif button.description.find(
menu_buttons[Language]['SubProjects_resume']) != -1 and\
len(button.description) != (len(
menu_buttons[Language]['SubProjects_resume'])):
RequiredAction = 'resume'
ProjectNumber = button.description.rsplit(' ', 1)[1]
for i in range(len(ProjectsNames)):
if AccountsFilesInfo[i][1] == ProjectsNames[int(ProjectNumber)]:
ProjectURL = AccountsFilesInfo[i][0]
with RunningScreenOutput.output_to(0, 0):
RunningScreenOutput.clear_cell()
!boinccmd --project $ProjectURL $RequiredAction
print('(OK) !boinccmd --project '
+ ProjectURL + ' ' + RequiredAction)
wait(0, 5, 250, 1, False)
elif button.description.find(
menu_buttons[Language]['SubProjects_nomorewus']) != -1 and\
len(button.description) != (
len(menu_buttons[Language]['SubProjects_nomorewus'])):
RequiredAction = 'nomorework'
ProjectNumber = button.description.rsplit(' ', 1)[1]
for i in range(len(ProjectsNames)):
if AccountsFilesInfo[i][1] == ProjectsNames[int(ProjectNumber)]:
ProjectURL = AccountsFilesInfo[i][0]
with RunningScreenOutput.output_to(0, 0):
RunningScreenOutput.clear_cell()
!boinccmd --project $ProjectURL $RequiredAction
print('(OK) !boinccmd --project '
+ ProjectURL + ' ' + RequiredAction)
wait(0, 5, 250, 1, False)
elif button.description.find(
menu_buttons[Language]['SubProjects_morewus']) != -1 and\
len(button.description) != (
len(menu_buttons[Language]['SubProjects_morewus'])):
RequiredAction = 'allowmorework'
ProjectNumber = button.description.rsplit(' ', 1)[1]
for i in range(len(ProjectsNames)):
if AccountsFilesInfo[i][1] == ProjectsNames[int(ProjectNumber)]:
ProjectURL = AccountsFilesInfo[i][0]
with RunningScreenOutput.output_to(0, 0):
RunningScreenOutput.clear_cell()
!boinccmd --project $ProjectURL $RequiredAction
print('(OK) !boinccmd --project '
+ ProjectURL + ' ' + RequiredAction)
wait(0, 5, 250, 1, False)
elif button.description.find(
menu_buttons[Language]['SubProjects_update']) != -1 and\
len(button.description) != (
len(menu_buttons[Language]['SubProjects_update'])):
RequiredAction = 'update'
ProjectNumber = button.description.rsplit(' ', 1)[1]
for i in range(len(ProjectsNames)):
if AccountsFilesInfo[i][1] == (
ProjectsNames[int(ProjectNumber)]):
ProjectURL = AccountsFilesInfo[i][0]
with RunningScreenOutput.output_to(0, 0):
RunningScreenOutput.clear_cell()
!boinccmd --project $ProjectURL $RequiredAction
print('(OK) !boinccmd --project '
+ ProjectURL + ' ' + RequiredAction)
wait(0, 5, 250, 1, False)
elif button.description.find(
menu_buttons[Language]['SubProjects_reset']) != -1 and\
len(button.description) != (
len(menu_buttons[Language]['SubProjects_reset'])):
RequiredAction = 'reset'
ProjectNumber = button.description.rsplit(' ', 1)[1]
for i in range(len(ProjectsNames)):
if AccountsFilesInfo[i][1] == (
ProjectsNames[int(ProjectNumber)]):
ProjectURL = AccountsFilesInfo[i][0]
with RunningScreenOutput.output_to(0, 0):
RunningScreenOutput.clear_cell()
!boinccmd --project $ProjectURL $RequiredAction
print('(OK) !boinccmd --project '
+ ProjectURL + ' ' + RequiredAction)
wait(0, 5, 250, 1, False)
# Submenu Tasks
elif button.description == menu_buttons[Language]['SubTasks_running']:
with RunningScreenOutput.output_to(2, 0):
RunningScreenOutput.clear_cell()
Tasks_infos()
elif button.description == menu_buttons[Language]['SubTasks_upload']:
with RunningScreenOutput.output_to(2, 0):
RunningScreenOutput.clear_cell()
print('not done yet !') # todo
pass
elif button.description == menu_buttons[Language]['SubTasks_error']:
with RunningScreenOutput.output_to(2, 0):
RunningScreenOutput.clear_cell()
print('not done yet !') # todo
pass
elif button.description == menu_buttons[Language]['SubTasks_aborted']:
with RunningScreenOutput.output_to(2, 0):
RunningScreenOutput.clear_cell()
print('not done yet !') # todo
pass
# Submenu System info
elif button.description == menu_buttons[Language]['SubSystem_hostinfo']:
with RunningScreenOutput.output_to(2, 0):
RunningScreenOutput.clear_cell()
!boinccmd --get_host_info
elif button.description == menu_buttons[Language]['SubSystem_CPU']:
with RunningScreenOutput.output_to(2, 0):
RunningScreenOutput.clear_cell()
!top -b -n 1 -o TIME
elif button.description == menu_buttons[Language]['SubSystem_GPU']:
with RunningScreenOutput.output_to(2, 0):
RunningScreenOutput.clear_cell()
!nvidia-smi
# Unknown button / no linked action
else:
with RunningScreenOutput.output_to(2, 0):
RunningScreenOutput.clear_cell()
display(HTML('<div style="background-color: #903030;padding: 5px;">'
+ button.description + ' has no linked action'
+ '</div>\n'))
# Date/time of last command
with RunningScreenOutput.output_to(3, 0):
RunningScreenOutput.clear_cell()
print (time.strftime('%d/%m/%Y %H:%M:%S'))
#--------------------------------
# Fonction: StartLog
#--------------------------------
# Analyzes Boinc's startup, waiting for benchmark result (max : 60 secs)
# Gives CPU and GPU infos
def StartLog():
OkBenchmark = False # Benchmark isn't done
tespera = 0
InfoCPU = ''
InfoGPU = ''
while not(OkBenchmark) and (tespera < 60):
# clear_output(wait = True)
f = open('stdoutdae.txt','r')
ClientMessages = f.read().splitlines()
f.close()
# Show log (ClientMessages) most recent first
ClientMessagestxt = ''
LenClientMessages = len(ClientMessages)
for j in range(LenClientMessages):
ClientMessagestxt = (ClientMessagestxt
+ str(LenClientMessages - j).zfill(4)
+ ": "
+ ClientMessages[LenClientMessages - j - 1]
+ '<br>')
# benchmark terminé ?
OkBenchmark |= (ClientMessages[LenClientMessages - j - 1]
.find('integer MIPS (Dhrystone)') > -1)
# présence GPU ?
if (ClientMessages[LenClientMessages - j - 1]
.find('[---] No usable GPUs found') > -1):
InfoGPU = "GPU: NO"
desde = (ClientMessages[LenClientMessages - j - 1]
.find('[---] OpenCL:'))
if (desde > -1):
hasta = (ClientMessages[LenClientMessages - j - 1]
.find('(driver'))
InfoGPU = ("GPU: "
+ ClientMessages[LenClientMessages - j - 1]\
[desde + 14:hasta])
desde = (ClientMessages[LenClientMessages - j - 1]
.find('[---] Processor:'))
# Infos CPU
if (desde > -1):
hasta = (ClientMessages[LenClientMessages - j - 1]
.find('[Family'))
InfoCPU = ("CPU: "
+ ClientMessages[LenClientMessages - j - 1]\
[desde + 17:hasta])
with StartingScreenOutput.output_to(1, 0):
StartingScreenOutput.clear_cell()
display(HTML(
'<div style="height: '
+ str(InterfaceHeight)
+ 'px;overflow: auto;">'
+ ClientMessagestxt
+ '</div>'))
# "Waiting for Boinc start sequence's end"
with StartingScreenOutput.output_to(0, 0):
StartingScreenOutput.clear_cell()
Title(InitialInfo[Language]['StartSequenceEnd'])
wait(tespera, tespera + 10, 250, 1, True)
tespera += 10 # boucle de 10 secondes * 6 max
return InfoCPU, InfoGPU
#------------------------------
# Fonction: Messages
#------------------------------
# Displays Boinc messages in inverted order (most recent first)
def Messages():
f = open('stdoutdae.txt', 'r')
ClientMessages = f.read().splitlines()
f.close()
ClientMessagestxt = ''
LenClientMessages = len(ClientMessages)
for j in range(LenClientMessages):
# # Limit the line lenght to 158 chars
# new_input = ""
# for k, letter in enumerate(
# ClientMessages[LenClientMessages - j - 1]):
# if k % 158 == 0:
# new_input += '<br>\n'
# new_input += letter
# ClientMessages[LenClientMessages - j - 1] = (
# new_input[5:])
# Construct final message string
ClientMessagestxt = (ClientMessagestxt
+ str(LenClientMessages-j).zfill(4)
+ " : "
+ ClientMessages[LenClientMessages - j - 1]
+ '<br>')
display(HTML('<div style="height: '
+ str(InterfaceHeight)
+ 'px;overflow: auto;">'
+ ClientMessagestxt + '</div>'))
#------------------------------
# Fonction: stdoutstate_infos
#------------------------------
def stdoutstate_infos():
!boinccmd --get_state > stdoutstate.txt
f = open('stdoutstate.txt', 'r')
ClientStatus = f.read().split("======== ")
f.close()
for i in range(len(ClientStatus)):
# Projects
if ClientStatus[i].startswith("Projects ========"):
ProjectsLogsBlocs = re.split('[0-9]+\) -----------\n',
ClientStatus[i])
del ProjectsLogsBlocs[0]
ProjectsNames = []
for j in range(len(ProjectsLogsBlocs)):
ProjectsNames.append(
ProjectsLogsBlocs[j][9:ProjectsLogsBlocs[j].index("\n")])
# Applications
if ClientStatus[i].startswith("Applications ========"):
AppsLogsBlocs = re.split('[0-9]+\) -----------\n',
ClientStatus[i])
del AppsLogsBlocs[0]
AppsNames = []
for j in range(len(AppsLogsBlocs)):
AppsNames.append(
AppsLogsBlocs[j][9:AppsLogsBlocs[j].index("\n")])
# Application versions
if ClientStatus[i].startswith("Application versions ========"):
AppsversionsLogsBlocs = re.split('[0-9]+\) -----------\n',
ClientStatus[i])
del AppsversionsLogsBlocs[0]
AppsversionsNames = []
for j in range(len(AppsversionsLogsBlocs)):
AppsversionsNames.append(
AppsversionsLogsBlocs[j][12:AppsversionsLogsBlocs[j]\
.index("\n")])
# Workunits
if ClientStatus[i].startswith("Workunits ========"):
WorkunitsLogsBlocs = re.split('[0-9]+\) -----------\n',
ClientStatus[i])
del WorkunitsLogsBlocs[0]
WorkunitsNames = []
for j in range(len(WorkunitsLogsBlocs)):
WorkunitsNames.append(
WorkunitsLogsBlocs[j][9:WorkunitsLogsBlocs[j].index("\n")])
# Tasks
if ClientStatus[i].startswith("Tasks ========"):
TasksLog = re.split('[0-9]+\) -----------\n', ClientStatus[i])
del TasksLog[0]
TasksNames=[]
for j in range(len(TasksLog)):
# ThisTaskName = str(j + 1).zfill(4) + ' : ' # Task number
ThisTaskName = str(j + 1) + ' : '
for k in range(len(Projects['URLs'])):
if (TasksLog[j].find(Projects['URLs'][k]) != -1):
ProjectNameFound = GetProjectNameFromURL(
Projects['URLs'][k])
ThisTaskName = ThisTaskName + ProjectNameFound
for k in range(len(WUStates['SearchString'])):
if (TasksLog[j].find(WUStates['SearchString'][k]) != -1):
if (k == 3): # "active_task_state: EXECUTING"
TaskPercentComplete = ''
WherePercent = (TasksLog[j]
.find('fraction done: '))
if (WherePercent != -1):
TaskPercentComplete = (
int(round(float(TasksLog[j]
[WherePercent + 15:
WherePercent + 19]) * 100)))
ThisTaskName = (ThisTaskName
+ ' ['
+ str(TaskPercentComplete)
+ '%]') # Progression
else: # State != running
ThisTaskName = (ThisTaskName
+ WUStates[Language][k])
TasksNames.append(ThisTaskName)
# Timestats
Timestats = ClientStatus[i].split('Time stats ========')[1]
return ProjectsLogsBlocs, ProjectsNames,\
AppsLogsBlocs, AppsNames,\
AppsversionsLogsBlocs, AppsversionsNames,\
WorkunitsLogsBlocs, WorkunitsNames,\
TasksLog, TasksNames,\
Timestats
#------------------------------
# Fonction: Timestats
#------------------------------
# Displays Boinc client stats
def func_Timestats():
ProjectsLogsBlocs, ProjectsNames,\
AppsLogsBlocs, AppsNames,\
AppsversionsLogsBlocs, AppsversionsNames,\
WorkunitsLogsBlocs, WorkunitsNames,\
TasksLog, TasksNames,\
Timestats = (stdoutstate_infos())
display(HTML('<div style="overflow: auto;">'
+ Timestats.replace("\n", "<br>")
+ '</div>'))
#------------------------------
# Fonction: Attached_infos
#------------------------------
# List attached projects in tabs
def Attached_infos():
ProjectsLogsBlocs, ProjectsNames,\
AppsLogsBlocs, AppsNames,\
AppsversionsLogsBlocs, AppsversionsNames,\
WorkunitsLogsBlocs, WorkunitsNames,\
TasksLog, TasksNames,\
Timestats = (stdoutstate_infos())
SubTabProjects = ipywidgets.widgets.Tab()
children = []
for k in range(len(ProjectsLogsBlocs)):
SubTabProjects.set_title(k, ProjectsNames[k])
content = (
'<div style="height: '
+ str(InterfaceHeight - 100)
+ 'px;overflow: auto;color: #000000;line-height: normal;">'
+ ProjectsLogsBlocs[k].replace("\n", "<br>")
+ '</div>'
)
children.append(ipywidgets.widgets.HTML(
# description = ProjectsNames[k], # (Useless) desc tag inside tab
value = content
)
)
SubTabProjects.children = children
display(SubTabProjects)
#------------------------------
# Fonction: Apps_infos
#------------------------------
# List projects apps in tabs
def Apps_infos():
ProjectsLogsBlocs, ProjectsNames,\
AppsLogsBlocs, AppsNames,\
AppsversionsLogsBlocs, AppsversionsNames,\
WorkunitsLogsBlocs, WorkunitsNames,\
TasksLog, TasksNames,\
Timestats = (stdoutstate_infos())
SubTabApps = ipywidgets.widgets.Tab()
children = []
for k in range(len(AppsLogsBlocs)):
SubTabApps.set_title(k, AppsNames[k])
content = (
'<div style="height: '
+ str(InterfaceHeight - 100)
+ 'px;overflow: auto;color: #000000;line-height: normal;">'
+ AppsLogsBlocs[k].replace("\n", "<br>")
+ '</div>'
)
children.append(ipywidgets.widgets.HTML(
# description = AppssNames[k], # (Useless) desc tag inside tab
value = content
)
)
SubTabApps.children = children
display(SubTabApps)
#------------------------------
# Fonction: Appversions_infos
#------------------------------
# List workunits in tabs
def Appversions_infos():
ProjectsLogsBlocs, ProjectsNames,\
AppsLogsBlocs, AppsNames,\
AppsversionsLogsBlocs, AppsversionsNames,\
WorkunitsLogsBlocs, WorkunitsNames,\
TasksLog, TasksNames,\
Timestats = (stdoutstate_infos())
SubTabAppversions = ipywidgets.widgets.Tab()
children = []
for k in range(len(AppsversionsLogsBlocs)):
SubTabAppversions.set_title(k, AppsversionsNames[k])
content = (
'<div style="height: '
+ str(InterfaceHeight - 100)
+ 'px;overflow: auto;color: #000000;line-height: normal;">'
+ AppsversionsLogsBlocs[k].replace("\n", "<br>")
+ '</div>'
)
children.append(ipywidgets.widgets.HTML(
# description = AppversionsNames[k], # (Useless) desc tag inside tab
value = content
)
)
SubTabAppversions.children = children
display(SubTabAppversions)
#------------------------------
# Fonction: Workunits_infos
#------------------------------
# List workunits in tabs
def Workunits_infos():
ProjectsLogsBlocs, ProjectsNames,\
AppsLogsBlocs, AppsNames,\
AppsversionsLogsBlocs, AppsversionsNames,\
WorkunitsLogsBlocs, WorkunitsNames,\
TasksLog, TasksNames,\
Timestats = (stdoutstate_infos())
SubTabWorkunits = ipywidgets.widgets.Tab()
children = []
for k in range(len(WorkunitsLogsBlocs)):
SubTabWorkunits.set_title(k, WorkunitsNames[k])
content = (
'<div style="height: '
+ str(InterfaceHeight - 100)
+ 'px;overflow: auto;color: #000000;line-height: normal;">'
+ WorkunitsLogsBlocs[k].replace("\n", "<br>")
+ '</div>'
)
children.append(ipywidgets.widgets.HTML(
# description = ProjectsNames[k], # (Useless) desc tag inside tab
value = content
)
)
SubTabWorkunits.children = children
display(SubTabWorkunits)
#------------------------------
# Fonction: Tasks_infos
#------------------------------
# List running tasks in tabs
def Tasks_infos():
ProjectsLogsBlocs, ProjectsNames,\
AppsLogsBlocs, AppsNames,\
AppsversionsLogsBlocs, AppsversionsNames,\
WorkunitsLogsBlocs, WorkunitsNames,\
TasksLog, TasksNames,\
Timestats = (stdoutstate_infos())
TasksLogLength = len(TasksLog)
TasksLogBlocs = 1 + (TasksLogLength - 1) // 17
if TasksLogBlocs > 1: # More than 17 tasks
SubTabTasksNames = []
for Bl in range(TasksLogBlocs):
SubTabTasksNames.append(str(Bl * 17 + 1)
+ "-"
+ str(min(TasksLogLength, (Bl + 1) * 17)))
TabTasks = ipywidgets.widgets.Tab(layout="width='50px'")
grandchildren = []
for Bl in range(TasksLogBlocs):
# TasksNames[Bl * 17:min((Bl + 1) * 17, TasksLogLength)]
TabTasks.set_title(B1, SubTabTasksNames[B1])
SubSubTabTasks = ipywidgets.widgets.Tab(location = 'start')
grandchildren = []
for j in range(Bl * 17, min((Bl + 1) * 17, TasksLogLength)):
TabTasks.set_title(j, TasksNames[j])
content = (
'<div style="height: '
+ str(InterfaceHeight)
+ 'px;overflow: auto;color: #000000;line-height: normal;">'
+ TasksLog[j].replace("\n", "<br>")
+ '</div>'
)
grandchildren.append(ipywidgets.widgets.HTML(
# description = TasksNames[k], # (Useless) desc tag in tab
value = content
)
)
TabTasks.children = grandchildren
display(TabTasks)
else: # Less than 17 tasks
TabTasks = ipywidgets.widgets.Tab(location = 'start')
children = []
for j in range(len(TasksLog)):
TabTasks.set_title(j, TasksNames[j])
content = (
'<div style="height: '
+ str(InterfaceHeight)
+ 'px;overflow: auto;color: #000000;line-height: normal;">'
+ TasksLog[j].replace("\n", "<br>")
+ '</div>'
)
children.append(ipywidgets.widgets.HTML(
# description = TasksNames[k], # (Useless) desc tag in tab
value = content
)
)
TabTasks.children = children
display(TabTasks)
#------------------------------
# Fonction: ProjectOperations
#------------------------------
# Operations on projects
# Constructs actionbuttons for each project
def ProjectOperations():
ProjectsLogsBlocs, ProjectsNames,\
AppsLogsBlocs, AppsNames,\
AppsversionsLogsBlocs, AppsversionsNames,\
WorkunitsLogsBlocs, WorkunitsNames,\
TasksLog, TasksNames,\
Timestats = (stdoutstate_infos())
AccountsFilesInfo = AccountFilesInfos()
VBoxChildren = []
for i in range(len(ProjectsNames)):
for j in range(len(AccountsFilesInfo)):
if AccountsFilesInfo[j][1] == ProjectsNames[i]:
ProjectURL = AccountsFilesInfo[j][0]
Button_suspend_name = 'But_Suspend_' + str(i)
Button_suspend_name = ipywidgets.Button(
description = (
menu_buttons[Language]['SubProjects_suspend']
+ ' ' + (str(i))
),
layout = {'width': 'max-content'}
)
Button_suspend_name.on_click(button_action)
Button_resume_name = 'But_Resume_' + str(i)
Button_resume_name = ipywidgets.Button(
description = (
menu_buttons[Language]['SubProjects_resume']
+ ' ' + (str(i))
),
layout = {'width': 'max-content'}
)
Button_resume_name.on_click(button_action)
Button_nmw_name = 'But_NMW_' + str(i)
Button_nmw_name = ipywidgets.Button(
description = (
menu_buttons[Language]['SubProjects_nomorewus']
+ ' ' + (str(i))
),
layout = {'width': 'max-content'}
)
Button_nmw_name.on_click(button_action)
Button_mw_name = 'But_MW_' + str(i)
Button_mw_name = ipywidgets.Button(
description = (
menu_buttons[Language]['SubProjects_morewus']
+ ' ' + (str(i))
),
layout = {'width': 'max-content'}
)
Button_mw_name.on_click(button_action)
Button_update_name = 'But_update_' + str(i)
Button_update_name = ipywidgets.Button(
description = (
menu_buttons[Language]['SubProjects_update']
+ ' ' + (str(i))
),
layout = {'width': 'max-content'}
)
Button_update_name.on_click(button_action)
Button_reset_name = 'But_reset_' + str(i)
Button_reset_name = ipywidgets.Button(
description = (
menu_buttons[Language]['SubProjects_reset']
+ ' ' + (str(i))
),
layout = {'width': 'max-content'}
)
Button_reset_name.on_click(button_action)
Button_reset_name.style.button_color = '#903030'
Button_reset_name.style.font_weight = 'bold'
LineHBoxName = 'HBox_' + ProjectsNames[i]
LineHBoxName = ipywidgets.HBox([
ipywidgets.Label(value=str(i) + ' ' + ProjectsNames[i],
layout=ipywidgets.Layout(width='150px')),
Button_suspend_name,
Button_resume_name,
Button_nmw_name,
Button_mw_name,
Button_update_name,
Button_reset_name
])
VBoxChildren.append(LineHBoxName)
AllLinesVBox = ipywidgets.VBox()
AllLinesVBox.children = VBoxChildren
display(AllLinesVBox)
# -----------------------------------------------------------------------------
# Main program (start)
# -----------------------------------------------------------------------------
try:
InfoCPU, InfoGPU
except:
InfoCPU = ''
InfoGPU = ''
try:
running
except:
running = False
if running == False:
StartingScreenOutput = widgets.Grid(2, 1)
# "Updating Notebook, installing Boinc"
with StartingScreenOutput.output_to(0, 0):
Title(InitialInfo[Language]['Installing'])
with StartingScreenOutput.output_to(1, 0):
# System : machine name
os.system('hostname ' + Server)
os.system('echo ' + Server + ' > /etc/hostname')
os.system('echo "127.0.0.1 localhost ::1 localhost ip6-localhost\
ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix\
ff02::1 ip6-allnodes ff02::2 ip6-allrouters 172.28.0.2 '
+ Server + '" > /etc/hosts')
# System : update
!apt-get update
!apt-get upgrade
!apt-get dist-upgrade
!apt-get autoremove
!apt-get clean
!apt-get autoclean
# System : install Boinc and NVidia-SMI tool
!apt-get install boinc boinc-client
# !apt-get install nvidia-utils-470-server
# Drives & files : mount Google Drive
if not os.path.exists('/content/drive/MyDrive'):
drive.mount('/content/drive')
# Drives & files : accessing working folder (create if doesn't exist)
os.chdir('/content/drive/MyDrive')
if not os.path.exists('Boinc/' + Server):
os.makedirs('Boinc/' + Server)
os.chdir('Boinc/' + Server)
DataDir = repr(os.getcwd())
# Drives & files : copy useful executables to Google Drive
# filepath_boinccmd = ('/content/drive/MyDrive/Boinc/'
# + Server + '/boinccmd')
# if not os.path.exists(filepath_boinccmd)\
# and not os.path.isdir(filepath_boinccmd)\
# and not os.path.islink(filepath_boinccmd):
shutil.copy('/usr/bin/boinc', '.')
shutil.copy('/usr/bin/boinccmd', '.')
# shutil.copy('/usr/bin/nvidia-smi', '.')
# Drives & files : create default cc_config.xml
if not os.path.isfile('/content/drive/MyDrive/Boinc/'
+ Server
+ '/cc_config.xml'):
os.system('echo "'
+ UserCCConfig
+ '" > "/content/drive/MyDrive/Boinc/'
+ Server
+ '/cc_config.xml"')
# Drives & files : create default global_prefs_override.xml
if not os.path.isfile('/content/drive/MyDrive/Boinc/'
+ Server
+ '/global_prefs_override.xml'):
os.system('echo "'
+ UserGlobalPrefsOverride
+ '" > '
+ '"/content/drive/MyDrive/Boinc/'
+ Server
+ '/global_prefs_override.xml"')
# Drives & files : create default gui_rpc_auth.cfg
if not os.path.isfile('/content/drive/MyDrive/Boinc/'
+ Server
+ '/gui_rpc_auth.cfg'):
os.system('echo "'
+ RPC_Password
+ '" > '
+ '"/content/drive/MyDrive/Boinc/'
+ Server
+ '/gui_rpc_auth.cfg"')
# Drives & files : release all permissions
!chmod -R 777 *
# "Kill previous Boinc clients (if any)"
with StartingScreenOutput.output_to(0, 0):
Title(InitialInfo[Language]['KillPreviousBoinc'])
ActiveBoincClient = True
while ActiveBoincClient:
servicio = get_ipython().getoutput('boinccmd --quit').nlstr
ActiveBoincClient = (servicio != "can't connect to local host")
if ActiveBoincClient:
print('...')
wait(0, 5, 250, 1, False)
# Rotate logs. Keep the last 9.
try:
os.remove('stdoutdae9.txt') # 9
except:
pass
for i in range(9, 1, -1): # 9
try:
os.rename('stdoutdae' + str(i - 1) + '.txt',
'stdoutdae' + str(i) + '.txt')
except:
pass
try:
os.rename('stdoutdae.txt', 'stdoutdae1.txt')
except:
pass
# "Launch and set Boinc client"
with StartingScreenOutput.output_to(0, 0):
Title(InitialInfo[Language]['LaunchBoinc'])
with StartingScreenOutput.output_to(1, 0):
!boinc --daemon --redirectio --run_cpu_benchmarks --start_delay 30 \
--dir $DataDir
with StartingScreenOutput.output_to(0, 0):
wait(0, 5, 250, 1, False)
with StartingScreenOutput.output_to(1, 0):
!boinccmd --set_run_mode always
!boinccmd --set_gpu_mode always
!boinccmd --set_network_mode always
# !boinccmd --set_screensaver_mode off
# "Attach projects"
with StartingScreenOutput.output_to(0, 0):
Title(InitialInfo[Language]['AutoAttachProjects'])
with StartingScreenOutput.output_to(1, 0):
if not os.path.exists('projects'):
os.makedirs('projects')
AccountFilesInfo = AccountFilesInfos()
AttachedProjectsURLs = []
for h in range(len(AccountFilesInfo)):
AttachedProjectsURLs.append("'" + AccountFilesInfo[h][0] + "'")
for i in range(len(Projects['URLs'])):
ProjectAttach = Projects['Attach'][i]
ProjectURL = repr(Projects['URLs'][i])
ProjectAUTH = repr(Projects['AUTH'][i])
# Si le rattachement au projet est demandé
if ProjectAttach:
# Ce projet n'est pas encore attaché : on l'attache !
if not str(ProjectURL) in AttachedProjectsURLs:
print(InitialInfo[Language]['AutoDetachProjects']
+ Projects['URLs'][i])
!boinccmd --project_attach $ProjectURL $ProjectAUTH
# with StartingScreenOutput.output_to(0, 0):
# wait(0, 5, 250, 1, False)
# Le rattachement au projet n'est pas demandé
else:
# Ce projet est attaché : on le détache !
if str(ProjectURL) in AttachedProjectsURLs:
print(InitialInfo[Language]['AutoAttachProjects']
+ Projects['URLs'][i])
!boinccmd --project $ProjectURL detach
# with StartingScreenOutput.output_to(0, 0):
# wait(0, 5, 250, 1, False)
# "Waiting for Boinc start sequence's end"
with StartingScreenOutput.output_to(0, 0):
Title(InitialInfo[Language]['StartSequenceEnd'])
with StartingScreenOutput.output_to(1, 0):
while not os.path.exists('stdoutdae.txt'):
wait(0, 5, 250, 1, False)
InfoCPU, InfoGPU = StartLog()
clear_output(wait = True)
running = True
# -----------------------------------------------------------------------------
# Main : frontend interface
# -----------------------------------------------------------------------------
# Ugly fix to unlock auto width for ipywidgets.widgets.Tab() labels
# doc : https://github.com/jupyter-widgets/ipywidgets/issues/1905
display(HTML(
'<style>'
+ '.jupyter-widgets.widget-tab > .p-TabBar .p-TabBar-tab {'
+ 'flex: 0 1 auto'
+ '}'
+ '</style>'
))
# Interface : header
Title(App1 + ' | ' + App2, "left")
# Get Boinc version
!boinccmd --version > boinc_version.txt
boincversion_desc = open('boinc_version.txt', 'r')
boincversion = boincversion_desc.read()
boincversion_desc.close()
# Display header
display(HTML('<div style="display:flex;margin: 16px 0 16px 0;">\n'
+ '<div style="float: left;padding: 0 10px 0 0;">'
+ '<b>' + Server + '</b><br>\n&nbsp;</div>\n'
+ '<div style="float: left;padding: 0 10px 0 10px; '
+ 'border-left: 1px solid #c0c0c0;">'
+ InfoCPU + '<br>\n' + InfoGPU + '</div>\n'
+ '<div style="padding: 0 10px 0 10px; '
+ 'border-left: 1px solid #c0c0c0;">'
+ boincversion[22:] + '</div>\n'
+ '</div>\n'
# + '<div style="display: block;">'
# + '<b>Data dir : </b>' + DataDir + '</div>\n'
))
GoogleDriveSpace() # investigate : if put it in main header, displays out of it
display(HTML('<div style="display: block;">&nbsp;</div>\n')) # ugly separator
# Interface : Menu buttons
MenuOutput = widgets.Grid(2, 1)
# Main menu
MenuBoinc = ipywidgets.widgets.Button(
description = menu_buttons[Language]['MenuBoinc'],
layout = {'width': 'max-content'})
MenuBoinc.on_click(button_action)
MenuProjects = ipywidgets.widgets.Button(
description = menu_buttons[Language]['MenuProjects'],
layout = {'width': 'max-content'})
MenuProjects.on_click(button_action)
MenuTasks = ipywidgets.widgets.Button(
description = menu_buttons[Language]['MenuTasks'],
layout = {'width': 'max-content'})
MenuTasks.on_click(button_action)
MenuSystem = ipywidgets.widgets.Button(
description = menu_buttons[Language]['MenuSystem'],
layout = {'width': 'max-content'})
MenuSystem.on_click(button_action)
MainMenu = ipywidgets.HBox([
MenuBoinc,
MenuProjects,
MenuTasks,
MenuSystem
])
# Submenu Boinc
SubBoinc_messages = ipywidgets.widgets.Button(
description = menu_buttons[Language]['SubBoinc_messages'],
layout = {'width': 'max-content'})
SubBoinc_messages.on_click(button_action)
SubBoinc_getccstatus = ipywidgets.widgets.Button(
description = menu_buttons[Language]['SubBoinc_getccstatus'],
layout = {'width': 'max-content'})
SubBoinc_getccstatus.on_click(button_action)
SubBoinc_timestats = ipywidgets.widgets.Button(
description = menu_buttons[Language]['SubBoinc_timestats'],
layout = {'width': 'max-content'})
SubBoinc_timestats.on_click(button_action)
SubBoinc_filetransfers = ipywidgets.widgets.Button(
description = menu_buttons[Language]['SubBoinc_filetransfers'],
layout = {'width': 'max-content'})
SubBoinc_filetransfers.on_click(button_action)
SubBoinc_readcfg = ipywidgets.widgets.Button(
description = menu_buttons[Language]['SubBoinc_readcfg'],
layout = {'width': 'max-content'})
SubBoinc_readcfg.on_click(button_action)
SubBoinc_quit = ipywidgets.widgets.Button(
description = menu_buttons[Language]['SubBoinc_quit'],
layout = {'width': 'max-content'})
SubBoinc_quit.on_click(button_action)
SubBoinc_quit.style.button_color = '#903030'
SubBoinc_quit.style.font_weight = 'bold'
SubBoinc_start = ipywidgets.widgets.Button(
description = menu_buttons[Language]['SubBoinc_start'],
layout = {'width': 'max-content'})
SubBoinc_start.on_click(button_action)
SubBoinc_start.style.button_color = '#309030'
SubBoinc_start.style.font_weight = 'bold'
SubBoinc_menu_withquit = ipywidgets.HBox([
SubBoinc_messages,
SubBoinc_getccstatus,
SubBoinc_timestats,
SubBoinc_filetransfers,
SubBoinc_readcfg,
SubBoinc_quit
])
SubBoinc_menu_withstart = ipywidgets.HBox([
SubBoinc_messages,
SubBoinc_getccstatus,
SubBoinc_timestats,
SubBoinc_filetransfers,
SubBoinc_readcfg,
SubBoinc_start
])
# Submenu Projects
SubProjects_attached = ipywidgets.widgets.Button(
description = menu_buttons[Language]['SubProjects_attached'],
layout = {'width': 'max-content'})
SubProjects_attached.on_click(button_action)
SubProjects_apps = ipywidgets.widgets.Button(
description = menu_buttons[Language]['SubProjects_apps'],
layout = {'width': 'max-content'})
SubProjects_apps.on_click(button_action)
SubProjects_appversions = ipywidgets.widgets.Button(
description = menu_buttons[Language]['SubProjects_appversions'],
layout = {'width': 'max-content'})
SubProjects_appversions.on_click(button_action)
SubProjects_workunits = ipywidgets.widgets.Button(
description = menu_buttons[Language]['SubProjects_workunits'],
layout = {'width': 'max-content'})
SubProjects_workunits.on_click(button_action)
SubProjects_updateall = ipywidgets.widgets.Button(
description = menu_buttons[Language]['SubProjects_updateall'],
layout = {'width': 'max-content'})
SubProjects_updateall.on_click(button_action)
SubProjects_operations = ipywidgets.widgets.Button(
description = menu_buttons[Language]['SubProjects_operations'],
layout = {'width': 'max-content'})
SubProjects_operations.on_click(button_action)
SubProjects_menu = ipywidgets.HBox([
SubProjects_attached,
SubProjects_apps,
SubProjects_appversions,
SubProjects_workunits,
SubProjects_updateall,
SubProjects_operations,
])
# Submenu Tasks
SubTasks_running = ipywidgets.widgets.Button(
description = menu_buttons[Language]['SubTasks_running'],
layout = {'width': 'max-content'})
SubTasks_running.on_click(button_action)
SubTasks_upload = ipywidgets.widgets.Button(
description = menu_buttons[Language]['SubTasks_upload'],
layout = {'width': 'max-content'})
SubTasks_upload.on_click(button_action)
SubTasks_error = ipywidgets.widgets.Button(
description = menu_buttons[Language]['SubTasks_error'],
layout = {'width': 'max-content'})
SubTasks_error.on_click(button_action)
SubTasks_aborted = ipywidgets.widgets.Button(
description = menu_buttons[Language]['SubTasks_aborted'],
layout = {'width': 'max-content'})
SubTasks_aborted.on_click(button_action)
SubTasks_menu = ipywidgets.HBox([
SubTasks_running,
SubTasks_upload,
SubTasks_error,
SubTasks_aborted
])
# Submenu System infos
SubSystem_hostinfo = ipywidgets.widgets.Button(
description = menu_buttons[Language]['SubSystem_hostinfo'],
layout = {'width': 'max-content'})
SubSystem_hostinfo.on_click(button_action)
SubSystem_CPU = ipywidgets.widgets.Button(
description = menu_buttons[Language]['SubSystem_CPU'],
layout = {'width': 'max-content'})
SubSystem_CPU.on_click(button_action)
SubSystem_GPU = ipywidgets.widgets.Button(
description = menu_buttons[Language]['SubSystem_GPU'],
layout = {'width': 'max-content'})
SubSystem_GPU.on_click(button_action)
SubSystem_menu = ipywidgets.HBox([
SubSystem_hostinfo,
SubSystem_CPU,
SubSystem_GPU
])
with MenuOutput.output_to(0, 0):
display(MainMenu)
display(HTML('<div style="display: block;">&nbsp;</div>\n')) # ugly separator
# Interface : main output
RunningScreenOutput = widgets.Grid(4, 1)
# Default menu display
with MenuOutput.output_to(1, 0):
TestBoincRunning = get_ipython().\
getoutput('boinccmd --get_file_transfers').nlstr
isBoincRunning = (TestBoincRunning != "can't connect to local host")
if isBoincRunning:
display(SubBoinc_menu_withquit)
else:
display(SubBoinc_menu_withstart)
# Default output display
with RunningScreenOutput.output_to(0, 0):
RunningScreenOutput.clear_cell()
display(HTML('<div style="background-color: #606060;padding: 5px;">'
+ menu_buttons[Language]['SubBoinc_messages']
+ '</div>\n'))
with RunningScreenOutput.output_to(2, 0):
RunningScreenOutput.clear_cell()
Messages()
# Date/time of last command
with RunningScreenOutput.output_to(3, 0):
RunningScreenOutput.clear_cell()
print (time.strftime('%d/%m/%Y %H:%M:%S'))
@ElGuillermo
Copy link
Author

2022-04-18
As Colab will consider the notebook is stalled if no action takes place in the main interface and will shut it down within minutes, you may simulate actions in a secondary script pane below the main one.

A really dumb-but-efficient oneliner :

while True:pass

@PhilTheNet
Copy link

Depuis quelques jours ca plante au niveau des tabulations, tout est en linéaire...
Surement une maj d'une biblio chargée par défaut

@ElGuillermo
Copy link
Author

Depuis quelques jours ca plante au niveau des tabulations, tout est en linéaire... Surement une maj d'une biblio chargée par défaut

Hello PhilTheNet !
Je viens de relancer mon Colab (qui roupillait depuis des semaines) avec la même version de code que celle ci-dessus et... Ben je vois rien de bizarre :/

T'as peut-être un souci commun : des fois, le "notebook" garde une session ouverte après qu'elle a planté et ne parvient pas à la redémarrer correctement : elle tourne, mais il y a plein de bugs bizarres. Dans ce cas là, il faut l'arrêter manuellement et la relancer complètement.

Après, difficile de garantir qu'il n'y a pas effectivement un problème de biblio, notamment celle servant à faire la "mise en page" des onglets : elle est notoirement buggée :( Le vrai souci (et la raison pour laquelle j'ai un peu lâché l'affaire sur Colab), c'est qu'on ne sait jamais sur quel environnement on va tomber quand on crée un nouveau "notebook" : le matos (CPU/GPU) change, et j'ai l'impression qu'on n'a pas toujours accès aux mêmes dépôts Ubuntu selon les sessions : pas simple de garantir que "ça va marcher comme ça" à tous les coups.

Dans l'immédiat, vu que je ne parviens pas à reproduire l'erreur que tu décris, je ne peux pas faire grand chose :/

@PhilTheNet
Copy link

Salut,
Merci pour la réponse mais bon en fait je viens de me rendre compte en parcourant le code que j'utilise pas ce code mais une version modifiée du code original dans lequel j'ai rajouté la prise en compte de BAM!
:)

@ElGuillermo
Copy link
Author

Ah. C'est déjà pas mal de savoir qu'on n'a pas (forcément) un problème sur la même version... :D

Honnêtement, je ne crois pas que j'irai plus loin sur ce projet : Colab n'est manifestement pas fait pour tourner à 100% plus de quelques heures et a la fâcheuse tendance à être imprévisible quant à la déconnexion des sessions.

Si queqlu'un se sent d'améliorer mon bazar, qu'il se fasse plaisir ! :D

@PhilTheNet
Copy link

PhilTheNet commented Oct 22, 2022

Je me remet sur le coup et j'ai un pb bizarre tout marche bien avec ton script (et avec le mien) mais au bout d'une dizaine de mn les commandes du style !boinccmd --lacommande provoquent une erreur Authorization failure: -102, les taches boinc continuant de calculer
C'est pas une histoire de mot de passe j'ai essayé.
Il n'y a que la commande !boinccmd --version qui passe
Etrange...

@ElGuillermo
Copy link
Author

Hello ! Bizarre... A quoi l'erreur 112 correspond-elle ? Je ne trouve pas de référence dans Colab.
Par contre, ell eexiste dans boinccmd et correspondrait au fait que l'exécutable est lancé dans le dossier des données (voir : https://boinc.berkeley.edu/forum_thread.php?id=8298)...

@PhilTheNet
Copy link

Salut !
Authorization failure: -102 pas 112 (j'avais mis 112 mais j'ai modifié le post)

@ElGuillermo
Copy link
Author

Ah. C'est boinccmd ou le "notebook" qui renvoie l'erreur ?

@PhilTheNet
Copy link

PhilTheNet commented Oct 22, 2022

boinccmd
Un extrait du code de test que j'ai mis pour tenter de voir ce qui se passe 👍

!boinccmd --version => pas de soucis
!boinccmd --lacommande => en erreur au bout de qlqes minutes => Authorization failure: -102
time.sleep(10) => pour avoir le temps de voir les messages d'erreur

@ElGuillermo
Copy link
Author

ElGuillermo commented Oct 22, 2022

Mmm... à tous les coups tu tombes dans le délai de "veille" du notebook : s'il ne se passe rien sur la console, il "débranche".

Tente un truc : lance ton script principal et, dans la seconde console, en-dessous de la première dans laquelle tourne ton truc, entre ça :

while True:pass

... ça va lancer une boucle infinie qui "occupe" le notebook et l'empêche de déconnecter.
Le souci, c'est que Colab te demandera quand même de signaler ta présence en cliquant sur un popup de temps à autre, et il faudra stopper la boucle infinie pour interagir dans le script principal...

@PhilTheNet
Copy link

PhilTheNet commented Oct 22, 2022

je ne pense pas que cela soit ca parce que je j'active la routine de test toutes les 2 ou 3 mn

@ElGuillermo
Copy link
Author

Ah. Bizarre... Je peux mater ça "en vrai" tout à l'heure : là, je suis au taf :/

@PhilTheNet
Copy link

Oki
Thks

@PhilTheNet
Copy link

Bon en fait la connexion avec le rpc se coupe au bout de +-5mn même en faisant une boucle inifine d'appels rpc...

@ElGuillermo
Copy link
Author

Bah ! Cherche pas : c'est pourri de limitations dans la version gratuite. Le pire, c'est qu'elles ne sont pas "prévisibles" : un jour ça coupe au bout de 5 minutes, le lendemain au bout d'une demi-heure, trois jours après ça ne marche pas.
C'est pour ça que j'ai lâché l'affaire :/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment