tikz-gallery-generator

Custum build of stapix for tikz.pablopie.xyz

Commit
67ba2c9015ac86ec8d2503287d1300b48d2c570b
Parent
fbb8a822f6a46161bc600f248964ffd27de273c5
Author
Pablo <pablo-pie@riseup.net>
Date

[optimize] Index entries that should be skipped at startup

Diffstats

2 files changed, 102 insertions, 88 deletions

Status Name Changes Insertions Deletions
Modified src/log.rs 2 files changed 0 23
Modified src/main.rs 2 files changed 102 65
diff --git a/src/log.rs b/src/log.rs
@@ -27,7 +27,6 @@ pub(crate) enum Level {
 pub struct JobListLogger {
   total:            usize,
   count:            usize,
-  skipped:          usize,
   current_job_name: String,
 }
 
@@ -99,7 +98,6 @@ impl JobListLogger {
     Self {
       total: total_jobs,
       count: 0,
-      skipped: 0,
       current_job_name: String::with_capacity(STRING_CAPACITY),
     }
   }
@@ -132,13 +130,6 @@ impl JobListLogger {
     self.job_finished_impl();
   }
 
-  pub fn job_skipped(&mut self) {
-    self.count   += 1;
-    self.skipped += 1;
-
-    if self.count == self.total { self.log_skipped(); }
-  }
-
   fn inc_counter(&mut self, job_name: &str) {
     self.count += 1;
     self.current_job_name.clear();
@@ -152,20 +143,6 @@ impl JobListLogger {
       name  = self.current_job_name,
       empty = "",
     );
-
-    if self.count == self.total && self.skipped > 0 { self.log_skipped(); }
-  }
-
-  fn log_skipped(&self) {
-    use crate::FULL_BUILD_OPT;
-
-    print!("   {BOLD_YELLOW}Skipped{RESET} ");
-    if self.skipped == 1 {
-      print!("one entry. ");
-    } else {
-      print!("{} entries. ", self.skipped);
-    }
-    println!("Use {FULL_BUILD_OPT} to overwrite");
   }
 }
 
diff --git a/src/main.rs b/src/main.rs
@@ -54,7 +54,8 @@ fn main() -> ExitCode {
   };
 
   let mut full_build = false;
-  let mut num_threads = num_cpus::get() - 1;
+  let total_threads = num_cpus::get();
+  let mut num_threads = total_threads - 1;
   while let Some(arg) = args.next() {
     let mut is_valid_arg = false;
 
@@ -108,7 +109,7 @@ fn main() -> ExitCode {
       log::usage_config();
       return ExitCode::FAILURE;
     }
-    Ok(Ok(pics)) => if render_gallery(pics, full_build, num_threads).is_err() {
+    Ok(Ok(pics)) => if render_gallery(pics, full_build, num_threads, total_threads).is_err() {
       return ExitCode::FAILURE;
     },
   }
@@ -121,97 +122,133 @@ fn render_gallery(
   pics: Vec<GalleryEntry>,
   full_build: bool,
   num_threads: usize,
+  total_threads: usize,
 ) -> Result<(), ()> {
+  struct Job {
+    pic_id:     usize,
+    image_path: PathBuf,
+    thumb_path: PathBuf,
+    page_path:  PathBuf,
+  }
+
   let start = Instant::now();
 
-  // ========================================================================
-  for pic in &pics {
-    let mut target_path = PathBuf::from(TARGET_PATH);
-    target_path.push(IMAGES_PATH);
-    target_path.push(&pic.file_name);
+  let mut skipped = 0;
+  let mut jobs    = Vec::with_capacity(pics.len());
+  for (pic_id, pic) in pics.iter().enumerate() {
+    let mut image_path = PathBuf::from(TARGET_PATH);
+    image_path.push(IMAGES_PATH);
+    image_path.push(&pic.file_name);
 
-    if !full_build && !needs_update(pic, &target_path) {
-      copy(&pic.path, &target_path)?;
-    }
-  }
+    let thumb_path: PathBuf = ThumbPath(pic).into();
 
-  infoln!("Copied image files to the target directory");
+    let mut page_path = PathBuf::from(TARGET_PATH);
+    page_path.push(PAGES_PATH);
+    page_path.push(pic.file_name.clone() + ".html");
 
-  // ========================================================================
-  for pic in &pics {
     if pic.alt.is_empty() {
       warnln!(
         "Empty text alternative was specified for the file {name:?}",
         name = pic.file_name
       );
     }
-  }
 
-  // ========================================================================
-  let num_threads = cmp::min(num_threads, pics.len());
-  let rendering_pool = ThreadPool::with_name(
-    String::from("thumbnails renderer"),
-    num_threads
-  );
-  let (sender, reciever) = mpsc::channel();
-
-  infoln!("Rendering thumbnails... (using {num_threads} threads)");
-  let mut thumbs_logger = JobListLogger::new(pics.len());
-
-  let mut render_pool_count = 0;
-  for (id, pic) in pics.iter().enumerate() {
-    let thumb_path: PathBuf = ThumbPath(pic).into();
-
-    if !full_build && !needs_update(pic, &thumb_path) {
-      thumbs_logger.job_skipped();
-      continue;
+    if full_build || needs_update(pic, &image_path)
+                  || needs_update(pic, &thumb_path)
+                  || needs_update(pic, &page_path) {
+      jobs.push(Job { pic_id, image_path, thumb_path, page_path, });
+    } else {
+      skipped += 1;
     }
+  }
 
-    render_pool_count  += 1;
+  // ========================================================================
+  if !jobs.is_empty() {
+    infoln!("Rendering HTML files...");
+  }
+  let mut pages_logger = JobListLogger::new(1 + jobs.len());
 
-    let sender = sender.clone();
-    let pic = pic.clone();
+  pages_logger.job_started("index.html");
+    render_index(&pics).map_err(|_| ())?;
+  pages_logger.job_finished();
 
-    rendering_pool.execute(move || {
-      // NOTE: we need to send the picture id back so that the main thread
-      //       knows how to log the fact we finished rendering it
-      let _ = sender.send(render_thumbnail(&pic, &thumb_path).map(|()| id));
-    });
+  if jobs.is_empty() {
+    warnln!(
+      "Skipping all {total} entries: no update is required. Use {FULL_BUILD_OPT} to overwrite",
+      total = pics.len(),
+    );
+    log::finished(start.elapsed());
+    return Ok(());
   }
 
-  for _ in 0..render_pool_count {
-    let msg = reciever.recv();
-    // propagate the panic to the main thread: reciever.recv should
-    // only fail if some of the rendering threads panicked
-    if msg.is_err() { panic!("rendering thread panicked!"); }
+  for Job { pic_id, page_path, .. } in &jobs {
+    let pic = &pics[*pic_id];
+    pages_logger.job_started(&pic.file_name);
+      render_pic_page(pic, page_path).map_err(|_| ())?;
+    pages_logger.job_finished();
+  }
 
-    let job_id = msg.unwrap()?;
-    let pic = &pics[job_id];
-    thumbs_logger.job_started_and_finished(&pic.file_name);
+  // ========================================================================
+  for Job { pic_id, image_path, .. } in &jobs {
+    let pic = &pics[*pic_id];
+    copy(&pic.path, image_path)?;
   }
-  drop(thumbs_logger);
+
+  infoln!("Copied image files to the target directory");
 
   // ========================================================================
-  infoln!("Rendering HTML files...");
-  let mut pages_logger = JobListLogger::new(1 + pics.len());
+  let num_threads = cmp::min(num_threads, jobs.len());
+  let mut thumbs_logger = JobListLogger::new(jobs.len());
+
+  // NOTE: only spawn the threads if necessary
+  if num_threads > 1 {
+    infoln!("Rendering thumbnails... (using {num_threads}/{total_threads} threads)");
+    let rendering_pool = ThreadPool::with_name(
+      String::from("thumbnails renderer"),
+      num_threads,
+    );
+    let (sender, reciever) = mpsc::channel();
+
+    for Job { pic_id, thumb_path, .. } in &jobs {
+      let pic_id = *pic_id;
+      let thumb_path = thumb_path.clone();
+      let pic = pics[pic_id].clone();
+      let sender = sender.clone();
+
+      rendering_pool.execute(move || {
+        // NOTE: we need to send the picture id back so that the main thread
+        //       knows how to log the fact we finished rendering it
+        let _ = sender.send(
+          render_thumbnail(&pic, &thumb_path).map(|()| pic_id)
+        );
+      });
+    }
 
-  pages_logger.job_started("index page");
-    render_index(&pics).map_err(|_| ())?;
-  pages_logger.job_finished();
+    for _ in 0..jobs.len() {
+      let msg = reciever.recv();
+      // propagate the panic to the main thread: reciever.recv should
+      // only fail if some of the rendering threads panicked
+      if msg.is_err() { panic!("rendering thread panicked!"); }
 
-  for pic in pics {
-    let mut path = PathBuf::from(TARGET_PATH);
-    path.push(PAGES_PATH);
-    path.push(pic.file_name.clone() + ".html");
+      let pic_id = msg.unwrap()?;
+      let pic = &pics[pic_id];
+      thumbs_logger.job_started_and_finished(&pic.file_name);
+    }
+  } else {
+    infoln!("Rendering thumbnails... (using 1/{total_threads} thread)");
+    for Job { pic_id, thumb_path, .. } in &jobs {
+      let pic = &pics[*pic_id];
 
-    if !full_build && !needs_update(&pic, &path) {
-      pages_logger.job_skipped();
-      continue;
+      thumbs_logger.job_started(&pic.file_name);
+        render_thumbnail(pic, thumb_path)?;
+      thumbs_logger.job_finished();
     }
+  }
 
-    pages_logger.job_started(&pic.file_name);
-      render_pic_page(&pic, &path).map_err(|_| ())?;
-    pages_logger.job_finished();
+  // ==========================================================================
+  if skipped > 1 {
+    warnln!("Skipped {skipped}/{total} entries. Use {FULL_BUILD_OPT} to overwrite",
+           total = pics.len());
   }
 
   log::finished(start.elapsed());