Cache.json      Memory.json     Virtual-Memory.json
        Frontend.json   Pipeline.json
 
+The JSONs folder for a CPU model/family may be placed in the root arch
+folder, or may be placed in a vendor sub-folder under the arch folder
+for instances where the arch and vendor are not the same.
+
 Using the JSON files and the mapfile, 'jevents' generates the C source file,
 'pmu-events.c', which encodes the two sets of tables:
 
 
 #include <unistd.h>
 #include <stdarg.h>
 #include <libgen.h>
+#include <limits.h>
 #include <dirent.h>
 #include <sys/time.h>                  /* getrlimit */
 #include <sys/resource.h>              /* getrlimit */
         * Derive rest of table name from basename of the JSON file,
         * replacing hyphens and stripping out .json suffix.
         */
-       n = asprintf(&tblname, "pme_%s", basename(fname));
+       n = asprintf(&tblname, "pme_%s", fname);
        if (n < 0) {
                pr_info("%s: asprintf() error %s for file %s\n", prog,
                                strerror(errno), fname);
        for (i = 0; i < strlen(tblname); i++) {
                c = tblname[i];
 
-               if (c == '-')
+               if (c == '-' || c == '/')
                        tblname[i] = '_';
                else if (c == '.') {
                        tblname[i] = '\0';
 static FILE *eventsfp;
 static char *mapfile;
 
+static int is_leaf_dir(const char *fpath)
+{
+       DIR *d;
+       struct dirent *dir;
+       int res = 1;
+
+       d = opendir(fpath);
+       if (!d)
+               return 0;
+
+       while ((dir = readdir(d)) != NULL) {
+               if (!strcmp(dir->d_name, ".") || !strcmp(dir->d_name, ".."))
+                       continue;
+
+               if (dir->d_type == DT_DIR) {
+                       res = 0;
+                       break;
+               } else if (dir->d_type == DT_UNKNOWN) {
+                       char path[PATH_MAX];
+                       struct stat st;
+
+                       sprintf(path, "%s/%s", fpath, dir->d_name);
+                       if (stat(path, &st))
+                               break;
+
+                       if (S_ISDIR(st.st_mode)) {
+                               res = 0;
+                               break;
+                       }
+               }
+       }
+
+       closedir(d);
+
+       return res;
+}
+
 static int process_one_file(const char *fpath, const struct stat *sb,
                            int typeflag, struct FTW *ftwbuf)
 {
-       char *tblname, *bname  = (char *) fpath + ftwbuf->base;
+       char *tblname, *bname;
        int is_dir  = typeflag == FTW_D;
        int is_file = typeflag == FTW_F;
        int level   = ftwbuf->level;
        int err = 0;
 
+       if (level == 2 && is_dir) {
+               /*
+                * For level 2 directory, bname will include parent name,
+                * like vendor/platform. So search back from platform dir
+                * to find this.
+                */
+               bname = (char *) fpath + ftwbuf->base - 2;
+               for (;;) {
+                       if (*bname == '/')
+                               break;
+                       bname--;
+               }
+               bname++;
+       } else
+               bname = (char *) fpath + ftwbuf->base;
+
        pr_debug("%s %d %7jd %-20s %s\n",
                 is_file ? "f" : is_dir ? "d" : "x",
                 level, sb->st_size, bname, fpath);
 
-       /* base dir */
-       if (level == 0)
+       /* base dir or too deep */
+       if (level == 0 || level > 3)
                return 0;
 
+
        /* model directory, reset topic */
-       if (level == 1 && is_dir) {
+       if ((level == 1 && is_dir && is_leaf_dir(fpath)) ||
+           (level == 2 && is_dir)) {
                if (close_table)
                        print_events_table_suffix(eventsfp);