diff --git a/bd.yaml b/bd.yaml index 1ad693c..45bbde8 100644 --- a/bd.yaml +++ b/bd.yaml @@ -1,22 +1,27 @@ --- study: perftestakantu job: revision: str - + ntasks: int + run: - compiler_version: int + modules_list: str akantu_url: str + source_path: str job_space: ./createJobs.py run_space: - compiler_version: 12 - akantu_url: "https://gitlab.com/akantu/akantu.git" + modules_list: ['cmake/3.16.5', 'boost/1.73.0', 'mumps/5.3.3-mpi', 'parmetis/4.0.3', 'scotch/6.0.8-mpi', 'eigen/3.3.7', 'gcc/8.4.0', 'mvapich2/2.3.4', 'openblas/0.3.10', 'metis/5.1.0', 'netlib-scalapack/2.1.0', 'gmsh/4.5.4'] + akantu_url: "file:///home/richart/akantu-bare" + source_path: /home/richart/perf-test-akantu config_files: - compile_revision.sh + - material.dat + - bar.msh exec_file: launch.sh diff --git a/compile_revision.sh b/compile_revision.sh index 480ef56..3f1eb68 100755 --- a/compile_revision.sh +++ b/compile_revision.sh @@ -1,73 +1,84 @@ #!/usr/bin/bash set -euo pipefail akantu_src=$1 test_src=$2 revision=$3 usage() { - echo "$1 " + echo "$0 " } -if [ ! -e ${akantu_src} -o -z ${akantu_src} ]; then - usage() +if [ -z ${akantu_src} ]; then + usage exit 1 fi if [ ! -e ${test_src} -o -z ${test_src} ]; then - usage() + usage exit 2 fi wd=${PWD} prefix=$(mktemp --directory akantu.XXXXXXX --tmpdir) -git clone ${akantu_src} -b ${revision} --depth 1 ${prefix}/akantu +cd ${prefix} +git clone ${akantu_src} -n akantu + +cd akantu +git checkout ${revision} revision_date=$(git log -1 --format='%ct') cd ${prefix}/akantu mkdir build cd build echo "*** Configuring revision r${revision} ***" -cmake -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_CXX_COMPILE_FLAGS:STRING='-march=native' -DAKANTU_DEBUG:BOOL=OFF ${akantu_src} > ${wd}/configure-akantu-${revision}.log 2>&1 +cmake -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_CXX_FLAGS:STRING='-march=native' -DAKANTU_DEBUG:BOOL=OFF .. > ${wd}/configure-akantu-${revision}.log 2>&1 if [ ! $? -eq 0 ]; then exit 100 fi +make_opts="" +if [ x"SLURM_CPUS_PER_TASK" != "x" ]; then + make_opts="-j ${SLURM_CPUS_PER_TASK}" +fi + echo "*** Building revision r${revision} ***" -make > ${wd}/make-akantu-${revision} 2>&1 +make ${make_opts} > ${wd}/make-akantu-${revision} 2>&1 if [ ! $? -eq 0 ]; then exit 200 fi mkdir ${prefix}/build cd ${prefix}/build # 1413714847 epoch of tag v2.2 if [ $revision -lt 1413714847 ]; then echo "MAJOR 1" VERSION=1 else echo "MAJOR 2" VERSION=2 fi echo "*** Configuring test for r${revision} ***" cmake -DAKANTU_VERSION_MAJOR:STRING=$VERSION -DAkantu_DIR:PATH=${prefix}/akantu/build ${test_src} > ${wd}/configure-test-${revision} 2>&1 if [ ! $? -eq 0 ]; then exit 300 fi echo "*** Building test for r${revision} ***" make > ${wd}/make-test-${revision} 2>&1 if [ ! $? -eq 0 ]; then exit 400 fi + +cp perf_test ${wd} diff --git a/createJobs.py b/createJobs.py index 9529986..63b676b 100644 --- a/createJobs.py +++ b/createJobs.py @@ -1,13 +1,19 @@ +import git + def createJobs(base): # create of job template object job = base.Job() + + repo = git.Repo.init('/home/richart/akantu-bare', bare=True) + commits = repo.iter_commits() + # specify a range of jobs - job["revision"] = ['v1.0', 'v2.2'] + job["revision"] = [c.hexsha for c in commits] job["ntasks"] = [1] # creation of the jobs on the database n_insertion = base.createParameterSpace(job) print(f"Inserted {n_insertion} new jobs") diff --git a/explore.py b/explore.py index 55b9676..a343478 100644 --- a/explore.py +++ b/explore.py @@ -1,15 +1,18 @@ # load context import BlackDynamite as BD parser = BD.BDParser() params = parser.parseBDParameters() mybase = BD.Base(**params) j = mybase.Job() r = mybase.Run() # prepare a job and run j['revision'] = "v1.0" +j['ntasks'] = 1 -r['compiler'] = "gcc-13" +r['modules_list'] = ['cmake/3.16.5', 'boost/1.73.0', 'mumps/5.3.3-mpi', 'parmetis/4.0.3', 'scotch/6.0.8-mpi', 'eigen/3.3.7', 'gcc/8.4.0', 'mvapich2/2.3.4', 'openblas/0.3.10', 'metis/5.1.0', 'netlib-scalapack/2.1.0', 'gmsh/4.5.4'] +r['akantu_url'] = 'https://gitlab.com/akantu/akantu.git' +r['source_path'] = '/home/richart/perf-test-akantu' params["stdout"] = True mybase.manualLaunch(j, r, **params) diff --git a/launch.sh b/launch.sh index 179a172..8ab4626 100644 --- a/launch.sh +++ b/launch.sh @@ -1,6 +1,47 @@ #!/bin/bash -# bash ./compile_revision.sh __BLACKDYNAMITE__akantu_url__ . __BLACKDYNAMITE__revision__ +module load $(echo "__BLACKDYNAMITE__modules_list__" | tr "[,\[\]']" " ") -pushQuantity.py --quantity_id compute_time --value 100. --is_float --runid __BLACKDYNAMITE__run_id__ -updateRuns.py --run_id __BLACKDYNAMITE__run_id__ --updates "state = FINISHED" +bash ./compile_revision.sh __BLACKDYNAMITE__akantu_url__ __BLACKDYNAMITE__source_path__ __BLACKDYNAMITE__revision__ + +res=$? + +failure="FAILURE" +case $res in + 100) + failure="FAIL_CONFIG_AKANTU" + ;; + 200) + failure="FAIL_MAKE_AKANTU" + ;; + 300) + failure="FAIL_CONFIG_TEST" + ;; + 400) + failure="FAIL_MAKE_TEST" + ;; +esac + +if [ ! $res -eq 0 ]; then + updateRuns.py --updates "state = ${failure}" --truerun + exit $res +fi + +./perf_test | tee times.out + +res=$? + +if [ ! $res -eq 0 ]; then + updateRuns.py --updates "state = FAIL_TO_RUN" --truerun + exit $res +fi + +while IFS= read -r line; do + id=$(echo "$line" | awk '{ print $1 }') + time=$(echo "$line" | awk '{ print $2 }') + nb=$(echo "$line" | awk '{ print $3 }') + echo "pushQuantity.py --quantity_id time_${id} --values ${time} --is_float 1 --truerun" + echo "pushQuantity.py --quantity_id nb_${id} --values ${nb} --is_float 1 --truerun" +done < <(cat times.out | grep ' + ' | sed 's/ + \(.*\)\s*:\s*\([0-9.]*\)us - .*: \([0-9]*\)/\1 \2 \3/') + +updateRuns.py --updates "state = FINISHED" --truerun diff --git a/perf-test.cc b/perf-test.cc index 8044e9b..c2fd818 100644 --- a/perf-test.cc +++ b/perf-test.cc @@ -1,285 +1,289 @@ /** * @file scalability_test.cc * @author Nicolas Richart * @date Tue Feb 22 09:35:58 2011 * * @brief Test de scalability * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include #include #include /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #define _AKANTU_VERISON \ ((10000 * AKANTU_VERSION_MAJOR) + (100 * AKANTU_VERSION_MINOR)) #if (((AKANTU_VERSION_MAJOR >= 2) && (AKANTU_VERSION_MINOR >= 1)) || \ (AKANTU_VERSION_MAJOR >= 3)) # include "aka_array.hh" #else # include "aka_vector.hh" #endif //#define DUMPS_energy //#define DUMPS_paraview #include "solid_mechanics_model.hh" #if _AKANTU_VERISON < 20301 # include "mesh.hh" # include "mesh_io.hh" # include "mesh_partition_scotch.hh" #endif #if _AKANTU_VERISON < 30000 # include "static_communicator.hh" #else # include "communicator.hh" #endif using namespace akantu; typedef std::chrono::high_resolution_clock clk; using std::chrono::duration_cast; using std::chrono::microseconds; +//#define AKANTU_VERSION_MAJOR 2 +using clk = std::chrono::high_resolution_clock; +using seconds = std::chrono::duration; +using milliseconds = std::chrono::duration; + //#define AKANTU_VERSION_MAJOR 2 class Chrono { public: inline void start() { _start = clk::now(); }; - inline void store_time(const std::string & type) { + inline void store_time(const std::string &type) { clk::time_point _end = clk::now(); if (measures.find(type) == measures.end()) { - measures[type] = duration_cast(_end - _start); + measures[type] = _end - _start; nb_measures[type] = 1; } else { - measures[type] += duration_cast(_end - _start); + measures[type] += _end - _start; ++nb_measures[type]; } _start = clk::now(); } - virtual void printself(std::ostream & stream, int indent = 0) const { - std::string space; - for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) - ; + virtual void printself(std::ostream &stream, int indent = 0) const { + std::string space(indent, AKANTU_INDENT); + stream << space << "Chrono [" << std::endl; - std::map::const_iterator it; - for (it = measures.begin(); it != measures.end(); ++it) { - const std::pair & p = *it; - const unsigned int & nb_measure = nb_measures.find(p.first)->second; - stream << space << " + " << p.first << "\t: " << std::setw(7) - << std::fixed << std::setprecision(0) - << p.second.count() / double(nb_measure) << "us" << std::endl; + for (auto && measure : measures) { + const unsigned int &nb_measure = nb_measures.find(measure.first)->second; + stream << space << " + " << measure.first << "\t: " << std::setw(25) + << std::fixed << std::setprecision(16) + << measure.second.count() / double(nb_measure) + << "us - nb_repetition: " << nb_measure << std::endl; } stream << space << "]" << std::endl; } private: clk::time_point _start; - std::map measures; + std::map measures; std::map nb_measures; }; -inline std::ostream & operator<<(std::ostream & stream, const Chrono & _this) { +inline std::ostream &operator<<(std::ostream &stream, const Chrono &_this) { _this.printself(stream); return stream; } +/* -------------------------------------------------------------------------- */ int main(int argc, char * argv[]) { debug::setDebugLevel(dblWarning); initialize("material.dat", argc, argv); #if _AKANTU_VERISON < 30000 StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); #else auto & comm = Communicator::getStaticCommunicator(); #endif Int psize = comm.getNbProc(); Int prank = comm.whoAmI(); /* -------------------------------------------------------------------------- */ UInt spatial_dimension = 2; UInt max_steps = 1000; Real time_factor = 0.8; const Real pulse_width = .5; const Real A = 0.01; Real width = 1; Real height = 0.2; Chrono chrono; chrono.start(); /* ------------------------------------------------------------------------ */ Mesh mesh(spatial_dimension); #if AKANTU_VERSION_MAJOR < 3 MeshPartition * partition = NULL; #endif if (prank == 0) { #if _AKANTU_VERISON < 20201 MeshIOMSH mesh_io; mesh_io.read("bar.msh", mesh); #else mesh.read("bar.msh"); #endif - chrono.store_time("read mesh"); + chrono.store_time("read_mesh"); } if (prank == 0) { #if AKANTU_VERSION_MAJOR < 3 && defined(AKANTU_PARALLEL) partition = new MeshPartitionScotch(mesh, spatial_dimension); partition->partitionate(psize); #endif } #if AKANTU_VERSION_MAJOR >= 3 mesh.distribute(); chrono.store_time("distribute"); #endif /// model initialization SolidMechanicsModel model(mesh); #if AKANTU_VERSION_MAJOR < 3 model.initParallel(partition); chrono.store_time("distribute"); #endif model.initFull(); - chrono.store_time("init full"); + chrono.store_time("init_full"); #if AKANTU_VERSION_MAJOR < 3 model.assembleMassLumped(); - chrono.store_time("lumped mass"); + chrono.store_time("lumped_mass"); #endif /// boundary conditions Real eps = 1e-16; #if AKANTU_VERSION_MAJOR < 2 const Vector & pos = mesh.getNodes(); Vector & boundary = model.getBoundary(); Vector & disp = model.getDisplacement(); #else const Array & pos = mesh.getNodes(); Array & boundary = model.getBlockedDOFs(); Array & disp = model.getDisplacement(); #endif UInt nb_nodes = mesh.getNbNodes(); for (UInt n = 0; n < nb_nodes; ++n) { Real x = pos(n, 0); // Sinus * Gaussian Real L = pulse_width; Real k = 0.1 * 2 * M_PI * 3 / L; disp(n, 0) = A * sin(k * x) * exp(-(k * x) * (k * x) / (L * L)); if(std::abs((std::abs(pos(n, 1)) - height/ 2.) <= eps )) boundary(n, 1) = true; if (std::abs(pos(n, 0) + width / 2.) <= eps) boundary(n, 0) = true; // if((std::abs(pos(i, 1) - height/2.) <= eps) || (std::abs(pos(i, 1) + // height/2.) <= eps)) boundary(i, 1) = true; } - chrono.store_time("boundary cond"); + chrono.store_time("bound_cond"); #if defined(DUMPS_paraview) model.addDumpField("displacement"); model.addDumpField("velocity"); model.addDumpField("acceleration"); #if AKANTU_VERSION_MAJOR >= 3 model.addDumpField("internal_force"); #else model.addDumpField("residual"); #endif model.addDumpField("blocked_dofs"); model.addDumpField("mass"); - chrono.store_time("init dumper"); + chrono.store_time("init_dumper"); #endif #if defined(DUMPS_energy) std::ofstream out; out.open("energies.csv"); out << "kinetic,potential" << std::endl; - chrono.store_time("init energy"); + chrono.store_time("init_energy"); #endif Real time_step = model.getStableTimeStep() * time_factor; model.setTimeStep(time_step); std::cout << "Time step: " << time_step << std::endl; - chrono.store_time("time step"); + chrono.store_time("time_step"); Real epot, ekin; for (UInt s = 1; s <= max_steps; ++s) { chrono.start(); #if (AKANTU_VERSION_MAJOR >= 3) model.solveStep(); // NonLinearSolver & nls = // model.getDOFManager().getNonLinearSolver("implicit"); UInt n_iter = // nls.get("nb_iterations"); Real error = nls.get("error"); std::cout << // n_iter << " -> " << error << std::endl; #else model.explicitPred(); model.updateResidual(); model.updateAcceleration(); model.explicitCorr(); #endif chrono.store_time("solve_step"); #if defined(DUMPS_energy) #if (((AKANTU_VERSION_MAJOR >= 2) && (AKANTU_VERSION_MINOR >= 2)) || \ (AKANTU_VERSION_MAJOR >= 3)) epot = model.getEnergy("potential"); ekin = model.getEnergy("kinetic"); #else epot = model.getPotentialEnergy(); ekin = model.getKineticEnergy(); #endif out << ekin << "," << epot << std::endl; chrono.store_time("energies"); #endif #if defined(DUMPS_paraview) model.dump(); chrono.store_time("paraview"); #endif } if (prank == 0) std::cout << chrono; finalize(); return EXIT_SUCCESS; }