reduce CPU usage dramatically
I noticed that on tilde.town users with a high botany score used up a lot of CPU cycles. I skimmed through the code and didn't immediately see any tight loops, but after profiling against a user's borrowed .botany directory I saw the culprit: the score increase thread. This thread was designed to increase the user's score by 1 every time the thread did an iteration of its infinite loop. It would sleep for an interval scaled *down* based on how high a user's generation bonus was. This meant that the sleep interval trended towards zero, creating a tight loop for high scoring users. This commit changes the code to use a constant sleep inteveral but scale the score increment *up* based on generation. I also removed the death check thread entirely since we were already checking for death in the score thread. I also short circuited the death check. This had the effect of reducing CPU load for a high scoring user by a factor of about 50.pull/53/head
parent
99c1fda072
commit
ed7498bd4a
22
botany.py
22
botany.py
|
@ -4,11 +4,9 @@ import time
|
|||
import pickle
|
||||
import json
|
||||
import os
|
||||
import random
|
||||
import getpass
|
||||
import threading
|
||||
import errno
|
||||
import uuid
|
||||
import sqlite3
|
||||
import menu_screen as ms
|
||||
from plant import Plant
|
||||
|
@ -16,7 +14,9 @@ from plant import Plant
|
|||
# TODO:
|
||||
# - switch from personal data file to row in DB
|
||||
# - is threading necessary?
|
||||
# - reduce CPU usage
|
||||
# - use a different curses window for plant, menu, info window, score
|
||||
|
||||
# notes from vilmibm
|
||||
|
||||
# there are threads.
|
||||
# - life thread. sleeps a variable amount of time based on generation bonus. increases tick count (ticks == score).
|
||||
|
@ -41,7 +41,6 @@ from plant import Plant
|
|||
# - exit
|
||||
# quits program
|
||||
|
||||
|
||||
# part of the complexity of all this is everything takes place in one curses window; thus, updates must be manually synchronized across the various logical parts of the screen.
|
||||
# ideally, multiple windows would be used:
|
||||
# - the menu. it doesn't change unless the plant dies OR the plant hits stage 5, then "harvest" is dynamically added.
|
||||
|
@ -91,25 +90,10 @@ class DataManager(object):
|
|||
|
||||
def start_threads(self,this_plant):
|
||||
# creates threads to save files every minute
|
||||
death_check_thread = threading.Thread(target=self.death_check_update, args=(this_plant,))
|
||||
death_check_thread.daemon = True
|
||||
death_check_thread.start()
|
||||
autosave_thread = threading.Thread(target=self.autosave, args=(this_plant,))
|
||||
autosave_thread.daemon = True
|
||||
autosave_thread.start()
|
||||
|
||||
def death_check_update(self,this_plant):
|
||||
# .1 second updates and lock to minimize race condition
|
||||
while True:
|
||||
is_dead = this_plant.dead_check()
|
||||
if is_dead:
|
||||
self.save_plant(this_plant)
|
||||
self.data_write_json(this_plant)
|
||||
self.update_garden_db(this_plant)
|
||||
self.harvest_plant(this_plant)
|
||||
this_plant.unlock_new_creation()
|
||||
time.sleep(.1)
|
||||
|
||||
def autosave(self, this_plant):
|
||||
# running on thread, saves plant every 5s TODO: this is unnecessary
|
||||
# and breaks shit probably
|
||||
|
|
20
plant.py
20
plant.py
|
@ -3,6 +3,8 @@ import os
|
|||
import json
|
||||
import threading
|
||||
import time
|
||||
import uuid
|
||||
import getpass
|
||||
|
||||
class Plant:
|
||||
# This is your plant!
|
||||
|
@ -187,6 +189,8 @@ class Plant:
|
|||
return rarity
|
||||
|
||||
def dead_check(self):
|
||||
if self.dead:
|
||||
return True
|
||||
# if it has been >5 days since watering, sorry plant is dead :(
|
||||
time_delta_watered = int(time.time()) - self.watered_timestamp
|
||||
if time_delta_watered > (5 * (24 * 3600)):
|
||||
|
@ -327,10 +331,12 @@ class Plant:
|
|||
|
||||
def life(self):
|
||||
# I've created life :)
|
||||
generation_bonus = round(0.2 * (self.generation - 1), 1)
|
||||
score_inc = 1 * (1 + generation_bonus)
|
||||
while True:
|
||||
if not self.dead:
|
||||
if self.watered_24h:
|
||||
self.ticks += 1
|
||||
self.ticks += score_inc
|
||||
if self.stage < len(self.stage_list)-1:
|
||||
if self.ticks >= self.life_stages[self.stage]:
|
||||
self.growth()
|
||||
|
@ -340,10 +346,10 @@ class Plant:
|
|||
# Do something
|
||||
pass
|
||||
if self.dead_check():
|
||||
# Do something else
|
||||
pass
|
||||
self.save_plant(this_plant)
|
||||
self.data_write_json(this_plant)
|
||||
self.update_garden_db(this_plant)
|
||||
self.harvest_plant(this_plant)
|
||||
this_plant.unlock_new_creation()
|
||||
# TODO: event check
|
||||
generation_bonus = round(0.2 * (self.generation - 1), 1)
|
||||
adjusted_sleep_time = 1 / (1 + generation_bonus)
|
||||
time.sleep(adjusted_sleep_time)
|
||||
|
||||
time.sleep(2)
|
||||
|
|
Loading…
Reference in New Issue