(****************************************************************************)
(*                           the diy toolsuite                              *)
(*                                                                          *)
(* Jade Alglave, University College London, UK.                             *)
(* Luc Maranget, INRIA Paris-Rocquencourt, France.                          *)
(*                                                                          *)
(* Copyright 2015-present Institut National de Recherche en Informatique et *)
(* en Automatique and the authors. All rights reserved.                     *)
(*                                                                          *)
(* This software is governed by the CeCILL-B license under French law and   *)
(* abiding by the rules of distribution of free software. You can use,      *)
(* modify and/ or redistribute the software under the terms of the CeCILL-B *)
(* license as circulated by CEA, CNRS and INRIA at the following URL        *)
(* "http://www.cecill.info". We also give a copy in LICENSE.txt.            *)
(****************************************************************************)
open Printf

module type Config = sig
  val avail  : int option
  val size : int
  val runs : int
  val affinity : Affinity.t
  val targetos : TargetOS.t
end
module Make(O:Config) = struct

let avail  = match O.avail with
| None -> 1
| Some n -> n

let gen_makefile () =
  let default_numthreads = avail in
  let default_numruns    =  O.runs in
  let logdir     = "LOGDIR        ?= logs\n" in
  let numthreads = sprintf "NUMTHREADS    ?= %i\n" default_numthreads in
  let numruns    = sprintf "NUMRUNS       ?= %i\n" default_numruns in
  let cpuinfo =
    match O.targetos with
    | TargetOS.Linux|TargetOS.Android8 -> "\tcat /proc/cpuinfo > $(LOGDIR)/log_cpuinfo\n"
    | TargetOS.AIX|TargetOS.FreeBsd ->
        "\techo 'CPUINFO unsupported for this OS' > $(LOGDIR)/log_cpuinfo\n"
    | TargetOS.Mac -> Warn.fatal "generateCrossDoc.ml does not support Mac"  in
  logdir ^
  numthreads ^
  numruns ^
  "\nall:\n" ^
  "\tmkdir -p $(LOGDIR)\n" ^
  "\t$(MAKE) $(MFLAGS) -C src\n" ^
  "\ttime sh -c \"cd src && sh run.sh -a $(NUMTHREADS) -r $(NUMRUNS)\\\n " ^
  "  > ../$(LOGDIR)/log_out 2> ../$(LOGDIR)/log_err\"\\\n" ^
  "  2> $(LOGDIR)/log_time\n" ^
  cpuinfo


let pp_os os =
  let open TargetOS in
  match os with
  | Linux -> "linux"
  | AIX   -> "AIX"
  | Mac   -> "MacOs"
  | FreeBsd -> "FreeBsd"
  | Android8 -> "android8"

let gen_readme chan  =
  let pl fmt = ksprintf (fun s -> fprintf chan "%s\n" s) fmt in
  let default_numthreads = avail in
  let default_numruns = O.runs in
  let default_size = O.size in
  pl   "This directory contains packaged files for running a set of" ;
  pl   "interesting litmus tests." ;
  pl "" ;
  pl "" ;
  pl "REQUIREMENTS:" ;
  pl "  unix shell (we use bash 3.1.17(1), most POSIX shells should work)" ;
  pl "  gcc       (we use gcc 4.1.2, any recent gcc should work)" ;
  pl "  GNU make   (we use GNU make 3.81)" ;
  pl "  C sources and ggc options have been generated for: %s"
    (pp_os O.targetos) ;
  pl "" ;
  pl "" ;
  pl "INSTRUCTIONS:" ;
  pl "" ;
  pl "- `make' at the top level will run tests, and produce 4 logfiles in" ;
  pl "   the LOGDIR subdirectory." ;
  pl "" ;
  pl "- make takes 3 arguments from shell:" ;
  pl "  LOGDIR (default logs): " ;
  pl "       Produced files are $(LOGDIR)/log_out, $(LOGDIR)/log_err" ;
  pl "       (which should usually be empty), $(LOGDIR)/log_cpuinfo (for" ;
  pl "       recording cpuinfo), and $(LOGDIR)/log_time (which records " ;
  pl "       total time elapsed). " ;
  pl "  NUMTHREADS (default %i):" default_numthreads ;
  pl "       The number of logical threads available. " ;
  pl "       The program attempts to run as many copies of the tests that would" ;
  pl "       fit in NUMTHREADS logical threads, eg NUMTHREADS=16 would allow us " ;
  pl "       to run 8 copies of 2-processor tests in parallel." ;
  begin match default_numthreads,O.affinity with
  | 0, Affinity.Incr _ ->
      pl "       The default value of 0 enables the automatic assignement" ;
      pl "       of NUMTHREAD to the number of logical processors of the" ;
      pl "       tested machine."
  | _,_ -> ()
  end ;
  pl "  NUMRUNS (default %i):" default_numruns ;
  pl "       Number of \"runs\", multiply by %i (in default configuration) for"
       default_size ;
  pl "       number of test iterations run (thus default is %i iterations)."
       (default_size * default_numruns);
  pl "" ;
  pl "" ;
  pl "BEYOND DEFAULTS" ;
  pl "  The tests have been generated by litmus, see" ;
  pl "  <http://diy.inria.fr/doc/litmus.html>" ;
  ()

let get_one_base srcs =
  match srcs with
  | [] -> "A"
  | x::xs ->
      let min =
        List.fold_left
          (fun min src ->
            if String.length src < String.length min then src
            else min)
          x xs in
      try Filename.chop_extension min with _ -> assert false


let gen_readme_src chan arch sources =
  let pl fmt = ksprintf (fun s -> fprintf chan "%s\n" s) fmt in
  pl
    "Tests produced by litmus for architecture %s on %s "
    (Archs.pp arch) (pp_os O.targetos) ;
  pl "" ;
  pl "COMPILING" ;
  pl "  with command 'make [-j N]' or 'sh comp.sh'" ;
  pl "" ;
  pl "RUNNING ALL TESTS" ;
  pl "  with command 'sh run.sh'. Test result on standard output." ;
  pl "" ;
  pl "RUNNING ONE TEST";
  let b = get_one_base sources in
  pl "  Tests are .exe files, for instance %s.exe, run it by './%s.exe'"
    b b ;
  pl "" ;
  let size = O.size in
  let nruns = O.runs in
  pl "RUNNING OPTIONS" ;
  pl "  Main options to the run.sh script and to .exe files:" ;
  pl "  -v     be verbose (can be repeated)." ;
  pl "  -a <n> number of (logical) processors available, default %i." avail ;
  begin match avail,O.affinity with
  | 0, Affinity.Incr _ ->
      pl "      The default value of 0 means that .exe files attempt" ;
      pl "      to infer the actual number of logical threads." ;
  | _ -> ()
  end ;
  pl "  -s <n> one run operates on arrays of size <n>, default %i."
    size ;
  pl "  -r <n> number of runs, default %i." nruns ;
  pl "" ;
  pl "  For more options see for instance './%s.exe -help' and litmus documentation" b ;
  pl "  <http://diy.inria.fr/doc/litmus.html>" ;
  ()
end
