diff --git a/admin.py b/admin.py
index afe4031..02c04e6 100644
--- a/admin.py
+++ b/admin.py
@@ -48,12 +48,12 @@ def setup_logging(levelstring):
     
     memlog = logging.getLogger('memlog%s' % levelstring)
     timestring = datetime.datetime.strftime( datetime.datetime.now(), '%Y-%m-%d-%A_%H-%M-%S')
-    memhandler = logging.FileHandler('logs/%s-%s-memory.log' % (levelstring, timestring))
-    memhandler.setFormatter(formatter)
-    while memlog.handlers:
-        memlog.removeHandler(memlog.handlers[0])
-    memlog.addHandler(memhandler)
-    memlog.setLevel('INFO')
+    #memhandler = logging.FileHandler('logs/%s-%s-memory.log' % (levelstring, timestring))
+    #memhandler.setFormatter(formatter)
+    #while memlog.handlers:
+        #memlog.removeHandler(memlog.handlers[0])
+    #memlog.addHandler(memhandler)
+    #memlog.setLevel('INFO')
 
     runlog = logging.getLogger('runlog%s' % levelstring)
     runhandler = logging.FileHandler('logs/%s-%s-run.log' % (levelstring, timestring))
diff --git a/board_static_functions.py b/board_static_functions.py
index d3cdb75..daa25dc 100644
--- a/board_static_functions.py
+++ b/board_static_functions.py
@@ -547,7 +547,7 @@ def analysize_board_divisions(board):
         chunks = get_illegal_chunks(board)
         memcheck(board,False, 'static - board illegal chunks gotten.')
         for chunk in chunks:
-            se = set([pos for pos in chunk if hintlist_has_start_or_end(board._bhints[pos])])
+            se = set([pos for pos in chunk if hintnum_has_start_or_end(board._bhints.store[pos])])
             #memcheck(board,False, 'static - adding illegal chunk len %d' % len(chunk))
             add_odd_poss(board, se)
             #memcheck(board,False, 'static - illegal chunk added')
diff --git a/config.py b/config.py
index 88a7a3f..ab14a77 100644
--- a/config.py
+++ b/config.py
@@ -75,7 +75,9 @@ do_static_analysis=True
 #cache_stat_keys.extend('newstyle_make_room_hints oldstyle_make_room_hints'.split())
 cache_stat_keys='allsols_hits allsols_misses getone_hits getone_misses bt_check_touched_opt_count \
 bt_check_touched_nobt_count bt_check_touched_req_count boardhash_bt_count bt_count bt_alley bt_movebacktrack bt_boardhash_count sqs_store_hit sqs_store_miss \
-cache_key_made binrows_existed binrows_new missing_hint_subroom_solutions removed_inferior_fromsolved_count removed_inferior_fromonesolved_count skipping_remaking_hintroom'.split()
+cache_key_made binrows_existed binrows_new missing_hint_subroom_solutions removed_inferior_fromsolved_count removed_inferior_fromonesolved_count skipping_remaking_hintroom \
+roomsolving_useful_time_total roomsolving_timeout_time_total \
+roomsolving_useful_time_thisloop roomsolving_timeout_time_thisloop'.split()
 reset_loop_stats_keys = []  #these will be reset every loop.
 for kind in ['optrooms', 'reqrooms', 'mrgrooms', 'absrooms', 'relrooms', ]:
     for status in ['failed', 'solved', 'implausible', ]:
@@ -280,21 +282,7 @@ do_deeptunnel_removal = True
 do_static_roomsolving = True
 smart_deadend= True
 
-absrooms = True
-#absrooms= False
-
-mrgrooms= True  
-#mrgrooms= False
 
-relrooms= True
-#relrooms= False
-
-smart_mrgrooms = False
-
-replace_rooms = True
-#replace reqrooms (for now) with versions including forced loops to lower
-#the number of entrances etc.
-#replace_rooms = False
 
 
 nevertheless_save_allhints = True
@@ -349,5 +337,20 @@ initial_static_timelimit = 0.01
 
 doprint = True
 remove_old_absrooms = True
-remove_old_absrooms = False
-logging_this_room = False
\ No newline at end of file
+#remove_old_absrooms = False
+
+replace_rooms = True
+#replace reqrooms (for now) with versions including forced loops to lower
+#the number of entrances etc.
+#replace_rooms = False
+
+absrooms = True
+#absrooms= False
+
+mrgrooms= True  
+#mrgrooms= False
+
+relrooms= True
+#relrooms= False
+
+smart_mrgrooms = False
diff --git a/room.py b/room.py
index 889721d..8b2dd7a 100644
--- a/room.py
+++ b/room.py
@@ -38,6 +38,7 @@ class Room(object):
         self.setup(poss, gates)
         
         #admin info
+        self.logging_this_room = False
         self.booked_hints_changed_sqs = []
         self.broken = False  #for simulated subroom solving/check touched solving
         #we mark a room broken if attempts to even make it at all fail
@@ -187,26 +188,30 @@ class Room(object):
         solid = getsolid_known(sol)
         self.all_solids.remove(solid)
     
+    def should_stop_solving(self):
+        #self.progenitor.start_progress < self.progenitor.start_cutoff and
+        return time.clock() > self.progenitor.allsolve_start + 1
+        return time.time()>self.timelimit
+    
     def solve(self, board, source=None, propagate = True):
         self.solvetext = ''
         self.allsolve_start=time.clock()
         self.setup_key()
         timeres = self.set_timelimit(source=source, board = board)
         if not self.skip_solving:
+            #if self.kind == 'absrooms' and self.all_ct > 500:
+                #import ipdb;ipdb.set_trace()
             res = get_all_sols(self, board, toplevel=True)
-            #if res == TIMELIMIT:
-                #if self.progenitor.start_progress >= self.progenitor.start_cutoff:
-                    #not sure why this happens 
-                    # $maybe after triggering timeout we do a bit more work?because sometimes we do more work
-                    #import ipdb;ipdb.set_trace()
             self.log_attempt(res, self._hintcount)
             self.solve_took = time.clock() - self.allsolve_start
             st = time.clock()
             self.set_sols(res, board, propagate = propagate)
             self.prop_took = time.clock() - st
-            if config.logging_this_room:self.timedesc += ' ' + self.describe_sols(sols = res)
+            if self.logging_this_room:self.timedesc += ' ' + self.describe_sols(sols = res)
             if self.has_real_sols():
-                if config.logging_this_room:
+                config.cache_stats['roomsolving_useful_time_thisloop'] += self.solve_took
+                config.cache_stats['roomsolving_useful_time_total'] += self.solve_took
+                if self.logging_this_room:
                     self.timedesc += ' solved in %0.6f '%(self.solve_took, )
                     if self.solve_took:
                         difzone =' (rate:%.2e)' % (self.difficulty / (self.solve_took * 10000))  #diff points per ms
@@ -219,8 +224,10 @@ class Room(object):
                     config.cache_stats['thisloop_solved_%s' % self.kind] += 1
                     config.cache_stats['allloops_solved_%s' % self.kind] += 1
             else:
-                if config.logging_this_room:
+                if self.logging_this_room:
                     self.timedesc += ' timeout %0.4f'%(self.solve_took)
+                    config.cache_stats['roomsolving_timeout_time_thisloop'] += self.solve_took
+                    config.cache_stats['roomsolving_timeout_time_total'] += self.solve_took
                     difzone =' (rate:<%.2e)' % (self.difficulty / (self.solve_took * 10000))  #diff points per ms
                     config.cache_stats['thisloop_failed_%s' % self.kind] += 1
                     config.cache_stats['allloops_failed_%s' % self.kind] += 1
@@ -228,12 +235,12 @@ class Room(object):
             self.prop_took = 0
             self.log_attempt(TIMELIMIT, self._hintcount)
             self.solve_took =  time.clock() - self.allsolve_start
-            if config.logging_this_room:
+            if self.logging_this_room:
                 self.timedesc += ' no res, alltime= %0.6f'%(self.solve_took)
                 difzone = ''
                 config.cache_stats['thisloop_implausible_%s' % self.kind] += 1
                 config.cache_stats['allloops_implausible_%s' % self.kind] += 1
-        if config.logging_this_room:self.timedesc += difzone
+        if self.logging_this_room:self.timedesc += difzone
         return timeres
        
     def setup_key(self):
@@ -298,35 +305,34 @@ class Room(object):
     
     def set_timelimit(self, source=None, board = None):
         self.skip_solving = False
-        if config.logging_this_room:self.timedesc = ''
+        if self.logging_this_room:self.timedesc = ''
         if source=='static':
-            self.skip_solving = False  #we set current attempt timelimit, but overide it by setting this true
             #in some cases, if it's just implausible
             if self._hintcount in self.hintcount2attempts:
                 #have seen this room before.  increase time allocation.
                 last_attempt=self.hintcount2attempts[self._hintcount][-1]
                 if last_attempt:
                     next_attempt = last_attempt * 4
-                    if config.logging_this_room:self.timedesc += ' next *=4'
+                    if self.logging_this_room:self.timedesc += ' next *=4'
                 else:
                     next_attempt = 0
-                    if config.logging_this_room:self.timedesc += ' leave at 0'
+                    if self.logging_this_room:self.timedesc += ' leave at 0'
                     self.current_attempt_timelimit = 0
                     self.skip_solving = True
                     return 0
             else:
                 #next_attempt = self.estimate_time_to_solve() / 1.2
                 next_attempt = 0.01
-                if config.logging_this_room:self.timedesc += ' | next set to 0.01'
+                if self.logging_this_room:self.timedesc += ' | next set to 0.01'
             if next_attempt >= config.static_timelimit:
-                if config.logging_this_room:self.timedesc += 'over limit. %0.f too high, set to zero.' % next_attempt
+                if self.logging_this_room:self.timedesc += 'over limit. %0.f too high, set to zero.' % next_attempt
                 self.current_attempt_timelimit = 0  #put zero in here so we just stop with this guy.
                 #we will book _hintcount, 0
                 self.skip_solving = True
                 return 0
             self.current_attempt_timelimit = next_attempt
             if next_attempt != 0.01:
-                if config.logging_this_room:self.timedesc += ' current: %0.2f' % (next_attempt)
+                if self.logging_this_room:self.timedesc += ' current: %0.2f' % (next_attempt)
             #book this here even if we skip it due to difficulty later.
             #now we have logged the "attempt"
             #but if it's absurd, don't actually spend any time on it.
@@ -334,13 +340,13 @@ class Room(object):
             if next_attempt < estimated:
                 self.current_attempt_timelimit = next_attempt
                 self.skip_solving = True
-                if config.logging_this_room:self.timedesc += ' | (impl would need %0.4f). set to zero' % estimated
+                if self.logging_this_room:self.timedesc += ' | (impl would need %0.4f). set to zero' % estimated
                 return 1  #meaning, tell the looper that we at least incremented something.
             #special invisible work time stuff for important areas:
             #this increases the attention paid to interesting stuff.
             if not self.allposs.isdisjoint(board.temporary_interesting_poss):
                 next_attempt *= 4
-                if config.logging_this_room:self.timedesc += '*=4 supercharge'
+                if self.logging_this_room:self.timedesc += '*=4 supercharge'
             self.timelimit = time.time() + next_attempt
             return 1
         elif source == 'check-touched-getone':
diff --git a/room_solver.py b/room_solver.py
index 0cafc6c..f92ad74 100644
--- a/room_solver.py
+++ b/room_solver.py
@@ -168,9 +168,9 @@ def get_all_sols(rm, board, toplevel=False, getone=False):
     if cacheres is not None:
         if toplevel and not getone:
             if cacheres == TIMELIMIT:
-                rm.solvetext += 'cached-timelimit'
+                if rm.logging_this_room:rm.solvetext += 'cached-timelimit'
             else:
-                rm.solvetext += 'cached-sols'
+                if rm.logging_this_room:rm.solvetext += 'cached-sols'
         return cacheres
     if config.profile_room_solver:
         rm.save_all_subroom_sols = False
@@ -300,20 +300,20 @@ def all_breakdown(rm, board, toplevel=False, getone=False, debug=False):
     #have_found_clean=False
     starts = get_room_starts_from_hints(rm, board)
     if toplevel:
-        rm.startcount = len(starts)
+        #rm.startcount = len(starts)
         rm.start_progress = 0
         #rm.start_cutoff = int(rm.startcount / 1.2)
         #rm.start_cutoff = rm.startcount + 1  #to disable the "feature"
-        rm.start_cutoff = 1000
+        #rm.start_cutoff = 1000
         if not getone:
-            rm.solvetext += '%d starts' % len(starts)
+            if rm.logging_this_room:rm.solvetext += '%d starts' % len(starts)
     while starts:
         breakinner = False
-        if (rm.progenitor.start_progress < rm.progenitor.start_cutoff) and time.time()>rm.timelimit:
+        if rm.should_stop_solving():
             return TIMELIMIT
         thisstart = starts.pop()
         if toplevel:rm.start_progress += 1
-        if toplevel and not getone:rm.solvetext += '-' + str(rm.start_progress)
+        if toplevel and  rm.logging_this_room and not getone:rm.solvetext += '-' + str(rm.start_progress)
         startsq, indv, outdv = thisstart
         if rm.all_ct == 1 and outdv not in EXITS:
             continue
@@ -374,7 +374,7 @@ def all_breakdown(rm, board, toplevel=False, getone=False, debug=False):
                 rm.gates.add(endgate)
                 rm.gatesqs.add(stop)
             rm.unset_many(covered)
-            if (rm.progenitor.start_progress < rm.progenitor.start_cutoff) and time.time()>rm.timelimit:
+            if rm.should_stop_solving():
                 if config.profile_room_solver:
                     backoutreason = 'middle-timeout'
                     rm.smh(override_text = '%s%s%s' % (rm.progenitor.hashid[:6], rm == rm.progenitor and '-parent' or '-child', backoutreason))
@@ -421,7 +421,7 @@ def all_breakdown(rm, board, toplevel=False, getone=False, debug=False):
                         continue
                     for ii, ordering in enumerate(subroom_orderings):
                         #an ordering is a sub order of the sub solutions.  are these necessarily valid if there are internal bumps?
-                        if (rm.progenitor.start_progress < rm.progenitor.start_cutoff) and ii%128==0 and time.time()>rm.timelimit:
+                        if ii % 128 == 0 and rm.should_stop_solving():
                             ordering=TIMELIMIT
                         if ordering==TIMELIMIT:
                             if config.profile_room_solver:
@@ -569,7 +569,7 @@ def all_orderings_of_subroomreses(rm, srr):
 
 def go_until_deadend_with_path(rm, startsq, indv, already_covered, took_start, already_path=None, illegal_count = 0):
     """returns a list of ([total_path, total_covered, end, took_end])"""
-    if (rm.progenitor.start_progress < rm.progenitor.start_cutoff) and time.time()>rm.timelimit:
+    if rm.should_stop_solving():
         return TIMELIMIT
     if not already_path:
         already_path=[]
diff --git a/room_utils.py b/room_utils.py
index 67f416a..223a2c8 100644
--- a/room_utils.py
+++ b/room_utils.py
@@ -5,24 +5,25 @@ from room_bits import *
 from board_utils import possible_from_poss
 
 def get_board_starts_from_hints(rm):
-    return set([rm.local2global(sq) for sq in rm.allsqs if hintlist_has_start(num2hints(rm._hints.store[sq]))])
+    return set([rm.local2global(sq) for sq in rm.allsqs if rm._hints.store[sq] & ALLSTART])
 
 def get_board_ends_from_hints(rm):
-    return set([rm.local2global(sq) for sq in rm.allsqs if hintlist_has_end(num2hints(rm._hints.store[sq]))])
+    return set([rm.local2global(sq) for sq in rm.allsqs if rm._hints.store[sq] & ALLEND])
 
 def get_board_starts_and_ends_from_hints(rm):
-    return set([rm.local2global(sq) for sq in rm.allsqs if hintlist_has_start_or_end(num2hints(rm._hints.store[sq]))])
+    return set([rm.local2global(sq) for sq in rm.allsqs if rm._hints.store[sq] & ALLSTARTEND])
 
-def hintlist_has_start(hintlist):
-    return any([hh[0]==START for hh in hintlist])
+def hintnum_has_start(hintnum):
+    return hintnum & ALLSTART
 
-def hintlist_has_end(hintlist):
-    return any([hh[1]==END for hh in hintlist])
+def hintnum_has_end(hintnum):
+    return hintnum & ALLEND
 
-def hintlist_has_start_or_end(hintlist):
-    return any([hh[0]==START or hh[1]==END for hh in hintlist])
+def hintnum_has_start_or_end(hintnum):
+    return hintnum & ALLSTARTEND
 
 def remove_many_se_hints_room(rm, sqs, board):
+    import ipdb;ipdb.set_trace()
     hints={}
     for sq in sqs:
         hints[sq]=[hh for hh in rm._hints[sq] if hh[0]==START or hh[1]==END]
@@ -299,7 +300,7 @@ def get_base_illegal_count(rm, took_start):
 def difficulty(rm):
     real_gates = len([g for g in rm.gatesqs if counthintsinnum(rm._hints.store[g]) > 1])
     solved_gates = rm.gsq_ct - real_gates
-    res = rm.overhint() ** 2 *  rm.all_ct ** 1.3 * (1 + real_gates) ** 1.8 * (1 + solved_gates) ** 1.3
+    res = rm.overhint() ** 1.2 *  rm.all_ct * (1 + real_gates) ** 1.4 * (1 + solved_gates) ** 1.2
     rm.difficulty = res  #store it here for immediate reference.
     return res
 
diff --git a/solve_all_rooms.py b/solve_all_rooms.py
index d268738..6854649 100644
--- a/solve_all_rooms.py
+++ b/solve_all_rooms.py
@@ -24,11 +24,14 @@ def solve_all_rooms(board, source='static'):
     for oset in board.odd_pos_sets:
         temporary.update(oset)
     board.temporary_interesting_poss = temporary
+    config.cache_stats['thisloop_useful_time'] = 0.0
+    config.cache_stats['thisloop_timeout_time'] = 0.0
     for ii, rm in enumerate(rmlist):
         if rm.all_sols is None or rm.all_solids==TIMELIMIT:
-            config.logging_this_room = False
+            rm.logging_this_room = False
             if ii % LOG_EVERY_II == 0:
-                config.logging_this_room = True
+                rm.logging_this_room = True
+            rm.logging_this_room = True
             prevhintcount = board._hintcount
             thisres =  rm.solve(board, source=source)
             allsolve = time.clock() - rm.allsolve_start
@@ -50,10 +53,10 @@ def solve_all_rooms(board, source='static'):
                     import ipdb;ipdb.set_trace()
             board.check_all()
             res += thisres
-            if ii % LOG_EVERY_II == 0:
+            if rm.logging_this_room:
                 #checkstop()
                 extratime = allsolve - rm.solve_took - rm.prop_took
-                extra = config.logging_this_room and rm.timedesc or ''
+                extra = rm.logging_this_room and rm.timedesc or ''
                 gainpart = gain and ('-%03d ' % (gain)) or '-    '
                 line = '%s%d/%d %s %s %s s:%s extra=%0.6f' % (gainpart, ii, rmlistlen, rm.basic_desc(), rm.profile_description(), extra, rm.solvetext, extratime)
                 print(line)
diff --git a/split_utils.py b/split_utils.py
index 65f80f8..ccb4d11 100644
--- a/split_utils.py
+++ b/split_utils.py
@@ -826,13 +826,13 @@ def divide_rows_into_rooms(board, method, target_poss=None, sizelimit=None, need
             break
     return rooms
 
-    
+
 
 def permutations_with_repeats(rm, dct, timelimit, level):
     """for a dict like {'a':2, 'b':1} ==> ((a,a,b),(a,b,a),(b,a,a))
     something like permutations with repeats.
     """
-    if (rm.progenitor.start_progress < rm.progenitor.start_cutoff) and time.time()>rm.timelimit:
+    if rm.should_stop_solving():
         return TIMELIMIT
     res=()
     if len(dct)==1:
diff --git a/static_analysis.py b/static_analysis.py
index f8edb64..bd9c084 100644
--- a/static_analysis.py
+++ b/static_analysis.py
@@ -86,12 +86,13 @@ def static_analysis(board):
                 badabsrooms = []
                 badrelrooms = []
                 for rm in board.allrooms:
-                    if rm.createdloop < board.loopnum - 3:
-                        if rm.kind == 'absrooms':
-                            #import ipdb;ipdb.set_trace()
-                            badabsrooms.append(rm)
-                        elif rm.kind == 'relrooms':
-                            badrelrooms.append(rm)
+                    if rm.kind in ['absrooms', 'relrooms']:
+                        if rm.current_attempt_timelimit >= 1.0:
+                            if rm.kind == 'absrooms':
+                                #import ipdb;ipdb.set_trace()
+                                badabsrooms.append(rm)
+                            elif rm.kind == 'relrooms':
+                                badrelrooms.append(rm)
                 if badabsrooms:
                     memcheck(board, False, 'deleting %d old absrooms.' % len(badabsrooms))
                     board.remove_rooms(badabsrooms)
