#!/usr/bin/perl # fah_client_stats v0.2 by level6 of LIE # ======================================== # This script will gather all Folding@Home stats from the clients defined in clients.txt. # It will then output the stats into TXT and HTML formated files, as well as an accumating log # for later study. # # You will need nc (NetCat) and jq (JSON query) installed for this. # # Edit client.txt, lines in format of "IP Address:Name" # # Set These (examples are below): # ---------------------------------------- # $folderName="CHANGEME"; # The name of the folding user # $teamName="CHANGEME"; # The name of the folding team # $baseDir="CHANGEME"; # The base directory in your website where the files will be stored # $inputDir="CHANGEME"; # Where the clients.txt file lives # $outputDir="CHANGEME"; # Where the TXT, HTML, and LOG files will go $folderName="level6"; $teamName="LIE (Lepers of Information Exchange)"; $baseDir="/var/www/html/www.leper.org/FAH"; $inputDir="$baseDir/$folderName"; $outputDir="$baseDir/$folderName"; # ---------------------------------------- # ======================================== # Make sure the user has edited this file before running if($folderName=~/CHANGEME/) { die("Please edit the default values int he script, first.\n\n"); } use File::Copy; # Read client information from client.txt and build a keyed hash open(CLIENTS,"<$inputDir/clients.txt") || die("ERROR opening $inputDir/clients.txt: $!\n\n"); while() { chop; ($value,$key,$os,$cores,$monitored)=split(':',$_); $ip_list{$key}=$value; $os_list{$key}=$os; $core_list{$key}=$cores; $mon_list{$key}=$monitored; } close(CLIENTS); # open the HTML, TXT, and LOG files for writing open(HTML,">$outputDir/client_stats.html_tmp") || die("ERROR opening $outputDir/client_stats.html_tmp: $!\n\n"); open(TXT,">$outputDir/client_stats.txt_tmp") || die("ERROR opening $outputDir/client_stats.txt_tmp: $!\n\n"); open(LOG,">>$outputDir/client_stats.log") || die("ERROR opening $outputDir/client_stats.log: $!\n\n"); # Get current date in RFC-3399 format $DTSTAMP=`/usr/bin/date --rfc-3339=s`; chop($DTSTAMP); $IndoorTempF=`/usr/bin/curl -s http://10.10.40.55/BERTHA/IndoorTemps.log|/usr/bin/grep Library |/usr/bin/tail -1|/usr/bin/cut -d: -f5`; chop($IndoorTemp); $OutdoorTempF=`/usr/bin/curl -s http://10.10.40.55/BERTHA/IndoorTemps.log|/usr/bin/grep WeatherManSays |/usr/bin/tail -1|/usr/bin/cut -d: -f5`; chop($OutdoorTemp); $OutdoorTempC=int(($OutdoorTempF - 32) * (5/9)); $IndoorTempC=int(($IndoorTempF - 32) * (5/9)); # Start building the HTML file print HTML "FAH Client Stats for $folderName of $teamName\n"; print HTML "
FAH Client Stats for $folderName of $teamName
\n"; print HTML "
Last Updated: $DTSTAMP
\n
\n"; print HTML "
Outside Temperature: $OutdoorTempF°F ($OutdoorTempC°C) | Server Room Temperature: $IndoorTempF°F ($IndoorTempC°C)
\n
\n"; print HTML "
\n"; print HTML "\n"; print HTML "\n"; # Start building the TXT file print TXT "Last Updated: $DTSTAMP\n\n==================\n\n"; # Run through each of the clients, alphabetically foreach $fah_name (sort keys %ip_list) { $fah_ip=$ip_list{$fah_name}; $fah_os=$os_list{$fah_name}; $fah_cores=$core_list{$fah_name}; $cpuTempString=""; $cpuFreqString=""; if($mon_list{$fah_name}=~/N/i) { $cpuTempString="unmonitored"; $cpuFreqString="unmonitored"; } else { $cpuTempFreqString=`cat $inputDir/clients/ClientReports.log|grep $fah_name|tail -1|cut -d: -f6`; chop($cpuTempFreqString); (@cpuTempFreqArr)=split(/;/,$cpuTempFreqString); for($i=0;$i<=$#cpuTempFreqArr;$i++) { ($temp,$freq)=split(/,/,$cpuTempFreqArr[$i]); $cpuTempString.=$temp.','; $cpuFreqString.=$freq.','; } chop($cpuTempString);chop($cpuFreqString); } # 2020-05-10T18:20:01-0500:studio5g:4:52.0°C,100;51.0°C,100;52.0°C,100;52.0°C,100 print LOG "$DTSTAMP:$fah_name:$fah_os:$fah_cores:$cpuFreqString:$cpuTempString:"; print TXT "Name: $fah_name\nOS: $fah_os\nCores: $fah_cores\nCPU Freqs: $cpuFreqString\nCPU Temps: $cpuTempString"; $cpuFreqString=~s/,/%MAX
/g; if(not $cpuFreqString=~/unmonitored/) { $cpuFreqString=~s/$/%MAX/; } $cpuTempString=~s/,/
/g; print HTML "\n"; print HTML "\n"; print HTML "\n"; # Connect to port 36330 on the client and gather information, saving it to local files for processing $dummy=`echo -e "info\x0dexit\x0d" | nc $fah_ip 36330 | egrep -v -e Welcome -e '>' -e PyON -e '\-\-\-'>$outputDir/$fah_ip-info.txt`; $dummy=`echo -e "slot-info\x0dexit\x0d" | nc $fah_ip 36330 | egrep -v -e Welcome -e '>' -e PyON -e '\-\-\-'>$outputDir/$fah_ip-slot_info.txt`; $dummy=`echo -e "queue-info\x0dexit\x0d" | nc $fah_ip 36330 | egrep -v -e Welcome -e '>' -e PyON -e '\-\-\-'>$outputDir/$fah_ip-queue_info.txt`; # Process the local files $numSlots=`cat $outputDir/$fah_ip-slot_info.txt | grep 'id\"' | wc -l`; chop($numSlots); $modelCPU=`cat $outputDir/$fah_ip-info.txt | grep 'CPU.,' | sed 's/.* \"//' | sed 's/\"],//'`; chop($modelCPU); print HTML "\n"; print TXT "Model of CPU: $modelCPU\nNumber of Slots: $numSlots\n"; print LOG "$modelCPU:$numSlots:"; $HTML_UserStr=''; $HTML_TeamStr=''; $HTML_ProjectStr=''; $HTML_TPFStr=''; $HTML_ProgressStr=''; $HTML_PPDStr=''; $clientPPD=0; # For each slot found for($slot=0;$slot<$numSlots;$slot++) { $dummy=`echo -e "simulation-info $slot\x0dexit\x0d" | nc $fah_ip 36330|egrep -v -e Welcome -e '>' -e PyON -e '\-\-\-'>$outputDir/$fah_ip-simulation_info_$slot.txt`; $PPD=`cat $outputDir/$fah_ip-queue_info.txt | jq -r 'map(select(.slot == "0$slot")) | .[] | .ppd'`; chop($PPD); $clientPPD+=$PPD; $totalPPD+=$PPD; $progress=`cat $outputDir/$fah_ip-simulation_info_$slot.txt | jq -r ".progress * 100" | xargs printf '%.2f'`; chop($progress); $TPF=`cat $outputDir/$fah_ip-simulation_info_$slot.txt | jq -r ".eta / ( .total_iterations - .iterations_done )"| xargs printf '%.2f'`; chop($TPF); $user=`cat $outputDir/$fah_ip-simulation_info_$slot.txt | jq -r ".user"`; chop($user); $team=`cat $outputDir/$fah_ip-simulation_info_$slot.txt | jq -r ".team"`; chop($team); $project=`cat $outputDir/$fah_ip-simulation_info_$slot.txt | jq -r ".project"`; chop($project); # We need to build up a string for the HTML to fit better into the table cell, at the end # $HTML_UserStr=$HTML_UserStr.'slot'.$slot.'='.$user.';
'; # $HTML_TeamStr=$HTML_TeamStr.'slot'.$slot.'='.$team.';
'; # $HTML_ProjectStr=$HTML_ProjectStr.'slot'.$slot.'='.$project.';
'; if(length($user)>0) { $HTML_UserStr=$user.'
'; } if(length($team)>0) { $HTML_TeamStr=$team.'
'; } $HTML_ProjectStr=$HTML_ProjectStr.'slot'.$slot.'='.$project.';
'; $HTML_TPFStr=$HTML_TPFStr.'slot'.$slot.'='.$TPF.' sec;
'; $HTML_ProgressStr=$HTML_ProgressStr.'slot'.$slot.'='.$progress.'%;
'; $HTML_PPDStr=$HTML_PPDStr.'slot'.$slot.'='.$PPD.';
'; # We can output to TXT and LOG as we go print TXT "Slot $slot - User: $user\nSlot $slot - Team: $team\nSlot $slot - Project: $project\n"; print TXT "Slot $slot - Estimated Time Per Fold: $TPF seconds\nSlot $slot - Progress: $progress %\n"; print TXT "Slot $slot - Estimated PPD: $PPD\n"; print LOG "$user,$project,$TPF,$PPD,$progress;"; } $HTML_ProjectStr=~s/;//g; $HTML_TPFStr=~s/;//g; $HTML_ProgressStr=~s/;//g; $HTML_PPDStr=~s/;//g; print HTML "\n"; print HTML "\n"; print HTML "\n"; print TXT "-----\n"; print LOG "\n"; } # Finish the HTML print HTML "
Name:OS:Cores:Core Freqs:Core Temps:Model:Slots:User:Project:TPF:Progress:PPD:
$fah_name$fah_os$fah_cores$cpuFreqString$cpuTempString$modelCPU$numSlots$HTML_UserStr$HTML_ProjectStr$HTML_TPFStr$HTML_ProgressStr$HTML_PPDStr
\n"; print HTML "
\n

Total PPD: $totalPPD


\n"; print HTML "
\n

Historic Log


\n"; print HTML "\n"; # Close all files close(LOG); close(TXT); close(HTML); # Move the temporary HTML and TXT files into permanent place in one shot move("$outputDir/client_stats.html_tmp","$outputDir/client_stats.html"); move("$outputDir/client_stats.txt_tmp","$outputDir/client_stats.txt"); # Exit cleanly exit(0);