Index: libcfa/src/algorithms/range_iterator.cfa
===================================================================
--- libcfa/src/algorithms/range_iterator.cfa	(revision 8157bde02e6d1039ff6b40dd3645d976ca644a29)
+++ libcfa/src/algorithms/range_iterator.cfa	(revision 8157bde02e6d1039ff6b40dd3645d976ca644a29)
@@ -0,0 +1,57 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// range_iterator.cfa --
+//
+// Author           : Thierry Delisle
+// Created On       : Tue Nov 30 13:06:22 2021
+// Last Modified By :
+// Last Modified On :
+// Update Count     :
+//
+
+
+
+void main(RangeParser & this) {
+	for() {
+		this._start = -1;
+		this._stop = -1;
+		int start_len = -1, stop_len = -1;
+		int ret = sscanf(this.text, "%u%n-%u%n", &this._start, &start_len, &stop, &stop_len);
+		switch(ret) {
+		case 0:
+			// Not a range, maybe a comma?
+			if(this.text[0] == ',') {
+				this.text ++;
+				continue;
+			}
+
+			serr | "Error: unexpected character in next range: '" | this.text |"'";
+			exit(2);
+		case 1:
+			this.text += start_len;
+			// Only one value, push it!
+			this.com = this._start;
+			suspend;
+			break;
+		case 2:
+			if(this._start > this._stop) {
+				serr | "Error: next range out of order '" | this.text |"'";
+				exit(2);
+			}
+			this.text += stop_len;
+			for(this.com i = this._start; this.com <= this._stop; this.com++) {
+				suspend;
+			}
+			break;
+		default:
+			serr | "Error reading next block: '" | this.text |"', returned" | ret;
+			exit(2);
+		}
+
+		if(this.text[0] == '\0') break;
+	}
+}
Index: libcfa/src/algorithms/range_iterator.hfa
===================================================================
--- libcfa/src/algorithms/range_iterator.hfa	(revision 8157bde02e6d1039ff6b40dd3645d976ca644a29)
+++ libcfa/src/algorithms/range_iterator.hfa	(revision 8157bde02e6d1039ff6b40dd3645d976ca644a29)
@@ -0,0 +1,26 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// range_iterator.hfa --
+//
+// Author           : Thierry Delisle
+// Created On       : Tue Nov 30 13:06:22 2021
+// Last Modified By :
+// Last Modified On :
+// Update Count     :
+//
+
+generator RangeIter {
+	const char * text;
+	int com;
+	int
+};
+
+void ?{}(RangeIter & this, const char * text) {
+	this.text = text;
+}
+
+static inline bool next(RangeIter & this) { return resume(this).com > 0; }
Index: libcfa/src/device/cpu.cfa
===================================================================
--- libcfa/src/device/cpu.cfa	(revision 03cdad65eb2b3bca310b5c87b7dacccd8553e117)
+++ libcfa/src/device/cpu.cfa	(revision 8157bde02e6d1039ff6b40dd3645d976ca644a29)
@@ -135,5 +135,6 @@
 		count++;
 	}
-	iterate_dir(path, lambda);
+	int ret = iterate_dir(path, lambda);
+	if(ret == ENOTDIR) return 0;
 
 	/* paranoid */ verifyf(count == max + 1, "Inconsistent %s count, counted %d, but max %s was %d", prefix, count, prefix, (int)max);
@@ -224,7 +225,7 @@
 
 struct raw_cache_instance {
-	idx_range_t range;
-	unsigned width;
-	unsigned char level;
+	idx_range_t range;	// A text description of the cpus covered
+	unsigned width;		// The number of cpus covered
+	unsigned char level;	// the cache level
 	// FIXME add at least size and type
 };
@@ -233,4 +234,6 @@
 static void ^?{}(raw_cache_instance & this) { free(this.range);}
 
+// Returns a 2D array of instances of size [cpu count][cache levels]
+// where cache level doesn't include instruction caches
 raw_cache_instance ** build_raw_cache_table(unsigned cpus, unsigned idxs, unsigned cache_levels)
 {
@@ -239,16 +242,26 @@
 	// TODO: this loop is broken, it only works if the present cpu start at 0 and are contiguous which is not guaranteed.
 	for(i; cpus) {
-		raw[i] = alloc(cache_levels);
-		void addcache(unsigned fidx, unsigned char level, idx_range_t range, size_t len) {
-			/* paranoid */ verifyf(level <= cache_levels, "Unexpected cache level %d on cpu %u index %u", (int)level, i, fidx);
-
-			unsigned idx = cache_levels - level;
-			raw_cache_instance & r = raw[i][idx];
-			r.range = strndup(range, len);
-			r.level = level;
-			const char * end;
-			r.width = read_width(range, len, &end);
-		}
-		foreach_cacheidx(i, idxs, addcache);
+		if (cache_levels > 0) {
+			raw[i] = alloc(cache_levels);
+			void addcache(unsigned fidx, unsigned char level, idx_range_t range, size_t len) {
+				/* paranoid */ verifyf(level <= cache_levels, "Unexpected cache level %d on cpu %u index %u", (int)level, i, fidx);
+
+				unsigned idx = cache_levels - level;
+				raw_cache_instance & r = raw[i][idx];
+				r.range = strndup(range, len);
+				r.level = level;
+				const char * end;
+				r.width = read_width(range, len, &end);
+			}
+			foreach_cacheidx(i, idxs, addcache);
+		}
+		else {
+			char buf[128];
+			snprintf(buf, 128, "0-%u", cpus);
+			raw[i] = alloc();
+			raw[i]->range = strndup(buf, 128);
+			raw[i]->level = 0;
+			raw[i]->width = cpus;
+		}
 	}
 
@@ -333,5 +346,5 @@
 		unsigned cache_levels = 0;
 		unsigned llc = 0;
-		{
+		if (idxs != 0) {
 			unsigned char prev = -1u;
 			void first(unsigned idx, unsigned char level, const char * map, size_t len) {
@@ -416,4 +429,5 @@
 		cpu_info.llc_map = entries;
 		cpu_info.hthrd_count = cpus;
+		cpu_info.llc_count = map_cnt;
 	}
 
Index: libcfa/src/device/cpu.hfa
===================================================================
--- libcfa/src/device/cpu.hfa	(revision 03cdad65eb2b3bca310b5c87b7dacccd8553e117)
+++ libcfa/src/device/cpu.hfa	(revision 8157bde02e6d1039ff6b40dd3645d976ca644a29)
@@ -23,9 +23,12 @@
 
 struct cpu_info_t {
-	 // array of size [hthrd_count]
+	// Array of size [hthrd_count]
 	const cpu_map_entry_t * llc_map;
 
-	 // Number of _hardware_ threads present in the system
+	// Number of _hardware_ threads present in the system
 	size_t hthrd_count;
+
+	// Number of distinct last level caches
+	size_t llc_count;
 };
 
