Skip to content

Commit

Permalink
Further hackery
Browse files Browse the repository at this point in the history
  • Loading branch information
rsheeter committed Dec 11, 2024
1 parent 6df9217 commit 86377c1
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 80 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Where in we pursue oxidizing [fontmake](https://github.com/googlefonts/fontmake)
For context around where fontmake came from see
[Mr B goes to Vartown](https://github.com/googlefonts/oxidize/blob/main/text/2023-10-18-mrb-goes-to-vartown.md).

Converts source to IR, and then IR to font binary. Aims to be safe, incremental, and fast.
Converts source to IR, and then IR to font binary. Aims to be safe and fast.

References

Expand Down
4 changes: 3 additions & 1 deletion fontc/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,9 @@ impl Args {
use crate::testdata_dir;

let input_source = testdata_dir().join(source).canonicalize().unwrap();
Self::new(build_dir, input_source)
let mut result = Self::new(build_dir, input_source);
result.emit_ir = true;
result
}

/// The input source to compile.
Expand Down
90 changes: 34 additions & 56 deletions fontc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,37 +173,41 @@ fn add_feature_ir_job(workload: &mut Workload) -> Result<(), Error> {
}

fn add_feature_comp_be_job(workload: &mut Workload) -> Result<(), Error> {
let work = FeatureCompilationWork::create();
if !workload.change_detector.should_skip_features() {
workload.add(FeatureCompilationWork::create());
workload.add(work);
} else {
todo!("skip features; mark complete");
workload.skip(work);
}
Ok(())
}

fn add_marks_be_job(workload: &mut Workload) -> Result<(), Error> {
let work = create_mark_work();
if !workload.change_detector.should_skip_features() {
workload.add(create_mark_work());
workload.add(work);
} else {
todo!("skip features; mark complete");
workload.skip(work);
}
Ok(())
}

fn add_gather_ir_kerning_be_job(workload: &mut Workload) -> Result<(), Error> {
let work = create_gather_ir_kerning_work();
if !workload.change_detector.should_skip_features() {
workload.add(create_gather_ir_kerning_work());
workload.add(work);
} else {
todo!("skip features; mark complete");
workload.skip(work);
}
Ok(())
}

fn add_kerns_be_job(workload: &mut Workload) -> Result<(), Error> {
let work = create_kerns_work();
if !workload.change_detector.should_skip_features() {
workload.add(create_kerns_work());
workload.add(work);
} else {
todo!("skip features; mark complete");
workload.skip(work);
}
Ok(())
}
Expand Down Expand Up @@ -395,7 +399,6 @@ mod tests {
/// the directory is deleted.
_temp_dir: TempDir,
build_dir: PathBuf,
args: Args,
work_executed: HashSet<AnyWorkId>,
fe_context: FeContext,
be_context: BeContext,
Expand All @@ -407,12 +410,6 @@ mod tests {
TestCompile::compile(source, |args| args)
}

fn compile_again(prior_compile: &TestCompile) -> TestCompile {
TestCompile::compile(prior_compile.args.source().to_str().unwrap(), |_| {
prior_compile.args.clone()
})
}

fn compile(source: &str, adjust_args: impl Fn(Args) -> Args) -> TestCompile {
let mut timer = JobTimer::new(Instant::now());
let _ = env_logger::builder().is_test(true).try_init();
Expand All @@ -435,7 +432,6 @@ mod tests {
let mut result = TestCompile {
_temp_dir: temp_dir,
build_dir,
args: args.clone(),
work_executed: HashSet::new(),
fe_context,
be_context,
Expand Down Expand Up @@ -491,8 +487,8 @@ mod tests {
&mut File::open(build_dir.join("loca.format")).unwrap(),
)
.into(),
raw_glyf: read_file(&build_dir.join("glyf.table")),
raw_loca: read_file(&build_dir.join("loca.table")),
raw_glyf: read_file(build_dir, Path::new("glyf.table")),
raw_loca: read_file(build_dir, Path::new("loca.table")),
}
}

Expand All @@ -510,39 +506,6 @@ mod tests {
}
}

/// Copy testdata => tempdir so the test can modify it
fn copy_testdata(from: impl IntoIterator<Item = impl AsRef<Path>>, to_dir: &Path) {
let from_dir = testdata_dir();

let mut from: VecDeque<PathBuf> = from.into_iter().map(|p| from_dir.join(p)).collect();
while let Some(source) = from.pop_back() {
let rel_source = source.strip_prefix(&from_dir).unwrap();
let dest = to_dir.join(rel_source);
assert!(
source.exists(),
"cannot copy '{source:?}'; it doesn't exist"
);

let dest_dir = if source.is_dir() {
dest.as_path()
} else {
dest.parent().unwrap()
};
if !dest_dir.exists() {
fs::create_dir_all(dest_dir).unwrap();
}

if source.is_file() {
fs::copy(&source, &dest).unwrap();
}
if source.is_dir() {
for entry in fs::read_dir(source).unwrap() {
from.push_back(entry.unwrap().path());
}
}
}
}

fn assert_compile_work(source: &str, glyphs: Vec<&str>) {
let result = TestCompile::compile_source(source);
let mut completed = result.work_executed.iter().cloned().collect::<Vec<_>>();
Expand Down Expand Up @@ -689,7 +652,22 @@ mod tests {
(result, (*glyph).clone())
}

fn read_file(path: &Path) -> Vec<u8> {
fn read_file(build_dir: &Path, path: &Path) -> Vec<u8> {
assert!(build_dir.is_dir(), "{build_dir:?} isn't a directory?!");
let path = build_dir.join(path);
if !path.exists() {
// When a path is missing it's very helpful to know what's present
eprintln!("Build dir tree");
let mut pending = VecDeque::new();
pending.push_back(build_dir);
while let Some(pending_dir) = pending.pop_front() {
for entry in fs::read_dir(pending_dir).unwrap() {
let entry = entry.unwrap();
eprintln!("{}", entry.path().to_str().unwrap());
}
}

}
assert!(path.exists(), "{path:?} not found");
let mut buf = Vec::new();
File::open(path).unwrap().read_to_end(&mut buf).unwrap();
Expand All @@ -698,17 +676,17 @@ mod tests {

fn read_ir_glyph(build_dir: &Path, name: &str) -> ir::Glyph {
let raw_glyph = read_file(
&build_dir
.join("glyph_ir")
build_dir,
&Path::new("glyph_ir")
.join(string_to_filename(name, ".yml")),
);
ir::Glyph::read(&mut raw_glyph.as_slice())
}

fn read_be_glyph(build_dir: &Path, name: &str) -> RawGlyph {
let raw_glyph = read_file(
&build_dir
.join("glyphs")
build_dir,
&Path::new("glyphs")
.join(string_to_filename(name, ".glyf")),
);
let read: &mut dyn Read = &mut raw_glyph.as_slice();
Expand Down
53 changes: 31 additions & 22 deletions fontc/src/workload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,34 @@ impl<'a> Workload<'a> {
);
}

/// Do all the task dependency bookkeeping but don't actually run the wokr
pub(crate) fn skip(&mut self, work: impl Into<AnyWork>) {
let work: AnyWork = work.into();
let id = work.id();
self.insert_nop(id, work.read_access());
}

fn insert_with_bookkeeping(&mut self, job: Job) {
trace!("insert_job {}{:?}", job.work.as_ref().map(|_| "").unwrap_or("(nop) "), job.id);

self.job_count += 1;
self.count_pending
.entry(job.id.discriminant())
.or_default()
.fetch_add(1, Ordering::AcqRel);
self.jobs_pending.insert(job.id.clone(), job);
}

fn insert_nop(&mut self, id: AnyWorkId, read_access: AnyAccess) {
self.insert_with_bookkeeping(Job {
id: id.clone(),
work: None, // we exist solely to be marked complete by also_complete
read_access, // We don't want to be deemed runnable prematurely
write_access: AnyAccess::Be(Access::None),
running: false,
});
}

pub(crate) fn insert(&mut self, id: AnyWorkId, job: Job) {
let also_completes = job
.work
Expand All @@ -142,32 +170,13 @@ impl<'a> Workload<'a> {

// We need pending entries for also-completes items so dependencies on them work
for id in also_completes.iter() {
self.jobs_pending.insert(
id.clone(),
Job {
id: id.clone(),
work: None, // we exist solely to be marked complete by also_complete
read_access: job.read_access.clone(), // We don't want to be deemed runnable prematurely
write_access: AnyAccess::Be(Access::None),
running: false,
},
);
self.count_pending
.entry(id.discriminant())
.or_default()
.fetch_add(1, Ordering::AcqRel);
self.insert_nop(id.clone(), job.read_access.clone());
}

self.job_count += 1 + also_completes.len();
self.jobs_pending.insert(id.clone(), job);
self.count_pending
.entry(id.discriminant())
.or_default()
.fetch_add(1, Ordering::AcqRel);

if !also_completes.is_empty() {
self.also_completes.insert(id.clone(), also_completes);
}

self.insert_with_bookkeeping(job);
}

fn complete_one(&mut self, id: AnyWorkId, expected_pending: bool) {
Expand Down

0 comments on commit 86377c1

Please sign in to comment.