2011-12-31 07:50:55 +00:00
< ? php
2012-01-02 08:46:21 +00:00
// script for submitting batches of LAMMPS jobs
//
// When a batch is submitted, this script runs the first job
// until 1 time step is completed;
// this verifies that the input files are OK and gives us
// an estimate of the FLOPS needed for the batch.
//
// These test executions are done in the directory
// project/lammps_test/USERID.
// We assume that lammps_test exists and contains the LAMMPS executable
2011-12-31 07:50:55 +00:00
error_reporting ( E_ALL );
ini_set ( 'display_errors' , true );
ini_set ( 'display_startup_errors' , true );
require_once ( " ../inc/util.inc " );
require_once ( " ../inc/submit_db.inc " );
require_once ( " ../inc/sandbox.inc " );
2012-01-02 08:46:21 +00:00
// test a LAMMPS job
//
// the current directory must contain
// structure_file
// lammps_script
// cmd_variables
2012-01-03 08:13:38 +00:00
// pot_files (zipped potential files)
2012-01-02 08:46:21 +00:00
//
// output: success flag, CPU time per step, est. disk usage per job
//
2012-01-02 08:54:28 +00:00
function lammps_est () {
2012-01-02 08:46:21 +00:00
$avg_cpu = 0 ;
$test_result = 0 ;
$descs = array ();
$pipes = array ();
2012-01-03 09:47:21 +00:00
$options = file ( " cmd_variables " );
$cmd = " ../lmp_linux " . $options [ 0 ];
2012-03-03 07:13:33 +00:00
//echo $cmd;
2012-01-02 08:46:21 +00:00
$p = proc_open ( " $cmd " , $descs , $pipes );
2012-01-03 09:47:21 +00:00
system ( " unzip pot.zip " );
2012-01-02 08:46:21 +00:00
while ( 1 ) {
if ( file_exists ( " log.1 " )) {
$avg_cpu = calc_step_cpu ( " log.1 " );
if ( $avg_cpu != 0 ) {
2012-01-02 10:30:06 +00:00
//echo "avg_cpu is ".$avg_cpu."\n";
2012-01-02 08:46:21 +00:00
proc_terminate ( $p );
$test_result = 1 ;
break ;
}
}
2012-01-02 10:30:06 +00:00
//echo "sleeping\n";
2012-01-02 08:46:21 +00:00
sleep ( 1 );
}
2012-03-06 04:53:38 +00:00
$total_steps = get_total_steps ( " cmd_variables " );
$disk_space = calc_est_size (
" lammps_script " , " structure_file " , " cmd_variables "
);
$total_cpu = $total_steps * $avg_cpu ;
2012-03-01 12:34:50 +00:00
return array ( $test_result , $total_cpu , $disk_space );
}
2012-03-06 04:53:38 +00:00
function get_total_steps ( $cmd_file ) {
$fd = fopen ( $cmd_file , " r " );
if ( ! $fd ) {
echo " can not open file $cmd_file\n " ;
exit ( - 1 );
}
$loopno = 1 ;
$looprun = 1 ;
while ( ! feof ( $fd )) {
$line = fgets ( $fd , 4096 );
if ( preg_match ( " /loopnumber \ s+ \ d+/ " , $line , $matches )
&& preg_match ( " / \ d+/ " , $matches [ 0 ], $no )
) {
$loopno = $no [ 0 ];
2012-03-01 12:34:50 +00:00
}
2012-03-06 04:53:38 +00:00
if ( preg_match ( " /looprun \ s+ \ d+/ " , $line , $matches )
and preg_match ( " / \ d+/ " , $matches [ 0 ], $no )
) {
2012-03-01 12:34:50 +00:00
$looprun = $no [ 0 ];
}
2012-03-06 04:53:38 +00:00
}
fclose ( $fd );
$total_steps = $loopno * $looprun ;
print " total_steps = " . $total_steps ;
return $total_steps ;
2012-03-01 12:34:50 +00:00
}
2012-03-06 04:53:38 +00:00
function calc_est_size ( $lammps_script , $structure_file , $cmd_file ){
$dump_types = 0 ;
$fd = fopen ( $lammps_script , " r " );
if ( ! $fd ){
2012-03-01 12:34:50 +00:00
echo " can not open file $lammps_script\n " ;
exit ( - 1 );
}
2012-03-06 04:53:38 +00:00
while ( ! feof ( $fd )){
$line = fgets ( $fd , 4096 );
if ( preg_match ( " /^ \ s*dump/ " , $line )
and preg_match_all ( " /dump \ S+ \ . \ w { 3}/ " , $line , $matches , PREG_PATTERN_ORDER )
) {
2012-03-01 12:34:50 +00:00
$dump_types = count ( $matches [ 0 ]);
break ;
}
}
fclose ( $fd );
print " dump_types= " . $dump_types ;
2012-01-02 08:46:21 +00:00
2012-03-06 04:53:38 +00:00
$structure_file_size = filesize ( $structure_file );
$fd = fopen ( $cmd_file , " r " );
if ( ! $fd ){
2012-03-01 12:34:50 +00:00
echo " can not open file $cmd_file\n " ;
exit ( - 1 );
}
print " structure_file_size= " . $structure_file_size ;
$loopno = 1 ;
2012-03-06 04:53:38 +00:00
while ( ! feof ( $fd )){
$line = fgets ( $fd , 4096 );
if ( preg_match ( " /loopnumber \ s+ \ d+/ " , $line , $matches )){
if ( preg_match ( " / \ d+/ " , $matches [ 0 ], $no )){
$loopno = $no [ 0 ];
2012-03-01 12:34:50 +00:00
}
}
}
fclose ( $fd );
print " loopno= " . $loopno ;
2012-03-06 04:53:38 +00:00
$est_size = $loopno * $structure_file_size * 0.8 * $dump_types ;
2012-03-01 12:34:50 +00:00
return $est_size ;
2012-01-02 08:46:21 +00:00
}
function calc_step_cpu ( $filename ) {
$fd = fopen ( " $filename " , " r " );
$start_line = " Step CPU flow_com avoo " ;
$start = 0 ;
$start_step = 1 ;
$cur_step = 1 ;
$avg_cpu = 0 ;
if ( ! $fd ) {
echo " fail to open file log.1 " ;
exit ( - 1 );
}
while ( ! feof ( $fd )) {
$line = fgets ( $fd , 4096 );
if ( strlen ( $line ) > strlen ( $start_line )
&& substr_compare ( $line , $start_line , 0 , strlen ( $start_line )) == 0
) {
$start = 1 ;
continue ;
}
if ( ! $start ) continue ;
$arr = preg_split ( " / \ s+/ " , $line );
if ( count ( $arr ) != 6 || ! is_numeric ( $arr [ 1 ])) {
continue ;
}
$step = ( int ) $arr [ 1 ];
$cpu = ( float ) $arr [ 2 ];
if ( $cpu == 0 ) {
$start_step = $step ;
} else {
$cur_step = $step ;
2012-03-01 12:34:50 +00:00
if ( $cur_step - $start_step >= 9 ) {
2012-01-02 08:46:21 +00:00
$avg_cpu = $cpu / ( $cur_step - $start_step );
//echo "avg_cpu is ".$avg_cpu;
break ;
}
}
}
return $avg_cpu ;
}
2012-01-03 09:47:21 +00:00
function area_select () {
return "
< select name = area >
< option value = \ " Air filtration \" >Air filtration</option>
< option value = \ " Water filtration \" >Water filtration</option>
< option value = \ " Ultra-low friction \" >Ultra-low friction</option>
</ select >
" ;
}
function show_submit_form ( $user ) {
2011-12-31 07:50:55 +00:00
page_head ( " Submit LAMMPS jobs " );
echo "
< form action = lammps . php >
< input type = hidden name = action value = prepare >
" ;
start_table ();
2012-03-02 06:12:36 +00:00
row2 ( " <strong>structure_file</strong><br><span class=note>structure_file*</span> " , sandbox_file_select ( $user , " structure_file " ));
row2 ( " <strong>lammps_script</strong><br><span class=note>lammps_script*</span> " , sandbox_file_select ( $user , " lammps_script " ));
row2 ( " <strong>cmdline_file</strong><br><span class=note>cmdline_file*</span><span class=note> ( List of command lines, one per job )</span> " , sandbox_file_select ( $user , " cmdline_file " ));
row2 ( " <strong>pot.zip</strong><br><span class=note>*.zip</span><span class-note> ( Zipped Potential files )</span> " , sandbox_file_select ( $user , " zip " ));
row2 ( " <strong>Area</strong> " , area_select ());
2011-12-31 07:50:55 +00:00
row2 ( " " , " <input type=submit value=Prepare> " );
end_table ();
2012-01-18 09:04:35 +00:00
echo " </form>
< p >
2012-03-03 07:13:33 +00:00
< a href = sandbox . php >< strong > File_Sandbox </ strong ></ a >
< a href = lammps . php >< strong > Job_Submit </ strong ></ a >
< a href = submit . php >< strong > Job_Control </ strong ></ a >
2012-01-18 09:04:35 +00:00
" ;
2011-12-31 07:50:55 +00:00
page_tail ();
}
// verify that an input file exists in sandbox, and return its physical path
//
function get_file_path ( $user , $name ) {
$fname = get_str ( $name );
// verify that the files exist in sandbox
//
$sbdir = sandbox_dir ( $user );
list ( $error , $size , $md5 ) = sandbox_parse_link_file ( " $sbdir / $fname " );
if ( $error ) error_page ( " no $name file " );
return sandbox_physical_path ( $user , $md5 );
}
function project_flops () {
$x = BoincUser :: sum ( " expavg_credit " );
if ( $x == 0 ) $x = 200 ;
$y = 1e9 * $x / 200 ;
return $y ;
}
2012-01-12 08:01:07 +00:00
// Estimate how long a batch will take.
// Let N = # jobs, M = # hosts
// If N < M we can start all the jobs more or less now,
// so let T = F/H, where H is the median FLOPS of the hosts.
// If N > M we'll have to do the jobs in stages,
// so let T = ceil(N/M)*F/H.
//
// Note: these are both extremely optimistic estimates
//
function estimated_makespan ( $njobs , $flops_per_job ) {
$nhosts = BoincHost :: count ( " expavg_credit > 1 " );
if ( $nhosts < 10 ) {
$median_flops = 2e9 ;
} else {
$n = $nhosts / 2 ;
$hs = BoincHost :: enum ( " expavg_credit>1 order by p_fpops limit 1 " );
$h = $hs [ 0 ];
$median_flops = $h -> p_fpops ;
}
if ( $njobs < $nhosts ) {
return $flops_per_job / $median_flops ;
} else {
$k = ( int )(( $njobs + $nhosts - 1 ) / $nhosts );
return $k * $flops_per_job / $median_flops ;
}
}
2011-12-31 07:50:55 +00:00
function prepare_batch ( $user ) {
$structure_file_path = get_file_path ( $user , 'structure_file' );
2012-03-02 06:12:36 +00:00
$command_file_path = get_file_path ( $user , 'lammps_script' );
2011-12-31 07:50:55 +00:00
$cmdline_file_path = get_file_path ( $user , 'cmdline_file' );
2012-03-02 06:12:36 +00:00
$pot_files_path = get_file_path ( $user , 'zip' );
2011-12-31 07:50:55 +00:00
$info = null ;
$info -> structure_file_path = $structure_file_path ;
$info -> command_file_path = $command_file_path ;
$info -> cmdline_file_path = $cmdline_file_path ;
2012-01-03 08:13:38 +00:00
$info -> pot_files_path = $pot_files_path ;
2012-01-03 09:47:21 +00:00
$info -> area = get_str ( " area " );
2011-12-31 07:50:55 +00:00
2012-01-02 08:46:21 +00:00
// get the directory in which to run the test,
// clear it out,
// and set up links to the input files
2011-12-31 07:50:55 +00:00
//
2012-01-02 08:46:21 +00:00
$test_dir = " ../../lammps_test/ $user->id " ;
2012-01-02 10:30:06 +00:00
//echo "test_dir is ".$test_dir;
2012-01-02 08:46:21 +00:00
if ( ! is_dir ( $test_dir )) {
mkdir ( $test_dir );
}
if ( ! chdir ( $test_dir )) {
error_page ( " Can't chdir " );
}
2012-01-02 10:30:06 +00:00
system ( " rm * " );
2012-01-02 08:46:21 +00:00
symlink ( $structure_file_path , " structure_file " );
symlink ( $command_file_path , " lammps_script " );
symlink ( $cmdline_file_path , " cmd_variables " );
2012-01-03 08:13:38 +00:00
symlink ( $pot_files_path , " pot_files " );
2012-01-02 08:54:28 +00:00
list ( $error , $est_cpu_time , $disk ) = lammps_est ();
2012-01-02 08:46:21 +00:00
2012-01-02 10:30:06 +00:00
if ( $error == 0 ) {
2012-01-02 08:46:21 +00:00
error_page ( " LAMMPS test failed " );
}
2012-01-02 10:30:06 +00:00
system ( " rm * " );
2012-01-02 08:54:28 +00:00
$info -> rsc_fpops_est = $est_cpu_time * 5e9 ;
2012-03-04 05:29:14 +00:00
$info -> rsc_fpops_bound = $rsc_fpops_est * 20 ;
2011-12-31 07:50:55 +00:00
2012-03-01 12:34:50 +00:00
$info -> rsc_disk_bound = $disk ;
2011-12-31 07:50:55 +00:00
$tmpfile = tempnam ( " /tmp " , " lammps_ " );
file_put_contents ( $tmpfile , serialize ( $info ));
// get the # of jobs
//
$njobs = count ( file ( $cmdline_file_path ));
2012-01-12 08:01:07 +00:00
$secs_est = estimated_makespan ( $njobs , $info -> rsc_fpops_est );
2011-12-31 07:50:55 +00:00
$hrs_est = number_format ( $secs_est / 3600 , 1 );
2012-03-06 04:53:38 +00:00
$client_mb = number_format ( $info -> rsc_disk_bound / 1e6 , 1 );
$server_mb = number_format ( $njobs * $info -> rsc_disk_bound / 1e6 , 1 );
2011-12-31 07:50:55 +00:00
page_head ( " Batch prepared " );
echo "
Your batch has $njobs jobs .
< p >
Estimated time to completion : $hrs_est hours .
< p >
Estimated client disk usage : $client_mb MB
< p >
Estimated server disk usage : $server_mb MB
< p >
" ;
show_button ( " lammps.php?action=submit&tmpfile= $tmpfile " , " Submit Batch " );
page_tail ();
}
2012-01-01 03:35:29 +00:00
function submit_job ( $app , $batch_id , $info , $cmdline , $i ) {
2012-03-04 05:29:14 +00:00
$cmd = " cd ../..; ./bin/create_work --appname $app->name --batch $batch_id --rsc_fpops_est $info->rsc_fpops_est --rsc_fpops_bound $info->rsc_fpops_bound " ;
2011-12-31 07:50:55 +00:00
if ( $cmdline ) {
$cmd .= " --command_line \" $cmdline\ " " ;
}
$cmd .= " --wu_name batch_ " . $batch_id . " _ " . $i ;
2012-01-02 10:30:06 +00:00
$cmd .= " " . basename ( $info -> structure_file_path );
$cmd .= " " . basename ( $info -> command_file_path );
2012-01-03 08:13:38 +00:00
$cmd .= " " . basename ( $info -> pot_files_path );
2012-03-03 07:13:33 +00:00
//echo "<br> $cmd\n";
2012-01-01 03:35:29 +00:00
2011-12-31 07:50:55 +00:00
$ret = system ( $cmd );
if ( $ret === FALSE ) {
error_page ( " can't create job " );
2012-03-06 04:53:38 +00:00
} else {
2012-03-03 07:13:33 +00:00
header ( 'Location: submit.php' );
}
2011-12-31 07:50:55 +00:00
}
function submit_batch ( $user , $app ) {
$tmpfile = get_str ( 'tmpfile' );
2012-01-01 03:35:29 +00:00
$x = file_get_contents ( " $tmpfile " );
$info = unserialize ( $x );
2011-12-31 07:50:55 +00:00
2012-03-02 07:08:08 +00:00
$njobs = 0 ;
2011-12-31 07:50:55 +00:00
$cmdlines = file ( $info -> cmdline_file_path );
2012-03-06 04:53:38 +00:00
foreach ( $cmdlines as $cmdline ){
if ( preg_match ( " /^ \ s*-var/ " , $cmdline )) {
$njobs ++ ;
}
2012-03-02 07:08:08 +00:00
}
2011-12-31 07:50:55 +00:00
$now = time ();
2012-03-02 07:08:08 +00:00
$batch_name = $info -> area . " _ " . date ( " Y-M-d H:m:s " );
2012-01-01 03:35:29 +00:00
2012-01-02 10:30:06 +00:00
$batch_id = BoincBatch :: insert (
2012-03-02 08:16:28 +00:00
" (user_id, create_time, njobs, name, app_id, state) values ( $user->id , $now , $njobs , ' $batch_name ', $app->id , " . BATCH_STATE_IN_PROGRESS . " ) "
2012-01-02 10:30:06 +00:00
);
// $batch_id=99;
2011-12-31 07:50:55 +00:00
$i = 0 ;
foreach ( $cmdlines as $cmdline ) {
2012-03-06 04:53:38 +00:00
if ( preg_match ( " /^ \ s*-var/ " , $cmdline )){
2012-03-02 07:08:08 +00:00
submit_job ( $app , $batch_id , $info , $cmdline , $i );
$i ++ ;
}
2011-12-31 07:50:55 +00:00
}
}
$user = get_logged_in_user ();
$user_submit = BoincUserSubmit :: lookup_userid ( $user -> id );
if ( ! $user_submit ) error_page ( " no submit access " );
2012-01-02 02:47:28 +00:00
$app = BoincApp :: lookup ( " name='lammps' " );
2011-12-31 07:50:55 +00:00
if ( ! $app ) error_page ( " no lammps app " );
if ( ! $user_submit -> submit_all ) {
$usa = BoincUserSubmitApp :: lookup ( " user_id= $user->id and app_id= $app->id " );
if ( ! $usa ) {
error_page ( " no submit access " );
}
}
$action = get_str ( 'action' , true );
switch ( $action ) {
2012-01-03 09:47:21 +00:00
case '' : show_submit_form ( $user ); break ;
2011-12-31 07:50:55 +00:00
case 'prepare' : prepare_batch ( $user ); break ;
case 'submit' : submit_batch ( $user , $app ); break ;
default : error_page ( " no such action $action " );
}
?>