             TM.reset();
         }
         start_index = end_index;
-        log_factor += 1;
-    }
-    */
+        threads_log += 1;
+    }
+    // process remaining "tail" bins
+    bin_index = MAX_ADJ_UNIONS_BINS;
+    end_index = queue_pos[bin_index];
+    size = end_index - start_index;
+    if (size) {
+        printf("(start_index, end_index): %d, %d\n", start_index, end_index);
+        printf("threads_log, bin_index: %d, %d\n", threads_log, bin_index);
+        threads_per = 1 << (threads_log-1); 
+        printf("threads_per: %d, size: %d\n", threads_per, size);
+        TM.start();
+        forAllEdgesAdjUnionImbalanced(hornet, hd_queue_info().d_edge_queue, start_index, end_index, op, threads_per, 1);
+        TM.stop();
+        TM.print("imbalanced queue processing:");
+        TM.reset();
+    }
+
     free(queue_sizes);
     free(queue_pos);
 }

            int binary_work_est = u_len*log_v;
            int intersect_work_est = u_len + v_len;
            //const int WORK_FACTOR = 100;
            const int WORK_FACTOR = 0; // force balanced-only
            int METHOD = (WORK_FACTOR*intersect_work_est >= binary_work_est);
            bin_index = (METHOD*MAX_ADJ_UNIONS_BINS/2)+(log_u*BINS_1D_DIM+log_v); 
            //bin_index = MAX_ADJ_UNIONS_BINS/2+((src.id() + dst.id())%(MAX_ADJ_UNIONS_BINS/2));

    const int LOG_OFFSET = 2; // seems optimal from testing a few inputs; tunable
    int threads_log = 1;
    // balanced kernel
    while ((threads_log < BALANCED_THREADS_LOGMAX) && (threads_log+LOG_OFFSET < BINS_1D_DIM)) 
    {
        bin_index = bin_offset+(threads_log+LOG_OFFSET)*BINS_1D_DIM;
        end_index = queue_pos[bin_index];
