Skip to content

Instantly share code, notes, and snippets.

@colabug
Last active February 8, 2022 12:33
Show Gist options
  • Save colabug/a7c140a33e031960ae3d to your computer and use it in GitHub Desktop.
Save colabug/a7c140a33e031960ae3d to your computer and use it in GitHub Desktop.
Performance Patterns Notes

Another series: DevBytes: Efficient Data Transfers

  • Reduce time between when user wants and gets data.
  • Reduce radio active time and fetch less data.
  • Never poll! GCM/signaling is better. Reduce frequency. Batch + prefetch.
  • Should use binary format instead of JSON, etc.
  • Largest gains can be found here -- based on the radio wakeups and keep alives until it goes back to sleep.
  • When: determine the refresh time requirements.
  • Use Battery Historian to track/find problems.
  • How: Prefetch, compress everything, batch
  • Don't sync too often.
  • Slow connections keep the pipes open even longer and drain the data/battery.
  • Do Now vs. Do Later
  • Don't sync on an interval.
  • Add a backoff algorithm when no new data appears
  • Use activity detection to determine when to fetch -- if they are running they don't care about your app (which might not apply to Africa).
  • Adjust based on state of device (GCMNetworkManager).
  • Network Traffic tool in AS.
  • TLDR; use GCMNetworkManager
  • User action is NOW. Everything else can be batched.
  • Can store the in a queue or content provider (to keep them around after an app restart).
  • When? Can set up a threshold or get notified when requests are already happening and piggyback.
  • Future requests. Tricky balance!
  • On 3G should be around 1-5MB of data
  • Data will be needed and used.
  • Prefetch as much as they might need in the next 1-2 minutes
  • When making your prefecthing logic -- optimize for the connection speed (e.g. fetch 3 images instead of 12 when on a slow connection)
  • Time your connection by using network speed (measured yourself)
  • Spinners are annoying -- don't make them wait!
  • Caching is key. Use the old data you've already fetched.
  • On a cold boot fetch cached data and kick off a server commands. Will still need to show something to the user.
  • Use a binary serialization format to persist the data.
  • Binary blob vs. DB. When you need to do queries binary doesn't make sense.
  • Gather Information: Get the network type; calculate how long it takes to fetch something, measure over time.
  • Make Adjustments: Determine thresholds to adapt to conditions
  • Threshold suggestions: 50th percentile, 90th, 99th
  • Test by throttling on the emulator
  • Use smaller files/assets
  • Often lessening the quality doesn't make the pic look worse
  • Serve different sizes
  • Don't use JSON/XML since they don't really compress
  • Networking tracking tools
  • "Kick Object Oriented to the curb"
  • When serialized format matches in memory format it bloats your serialized stream (array of structs). Causes larger file sizes and can't be compressed very well.
  • Struct of arrays - break up your classes and group based on the property (e.g. height/width) -- produces simple arrays of similar typed data.
  • Removes redundant property names from he serialized format (smaller file), similar data types are contiguous (easier to compress), separate out content for different types of compression (e.g. delta compression).
  • You can get faster serialization by using binary formats.
  • Stop memory churn.
  • Temporary objects that create and then died. Polluting/fragmenting the memory heap. Leads to a lot of GC events.
  • Rather than request and free, keep them in a pool of available objects. Repurpose an existing object from the pool.
  • Leads to stable allocations and small growth.
  • There's overhead when the pool needs more space. Create several at the same time instead of as you need it. Also pre allocate the pool.
  • Now we're back to manually allocating and freeing objects. Limit to high churn object sets.
  • Make sure to properly clean up memory (field variables -- no references to other stuff)
  • Allocation Tracker to profile.
  • Can set the interval -- longer intervals are better, but not too long.
  • Make it dynamic -- when the user is stationary don't need to keep checking.
  • Set fastest interval avoids a flood of responses for GPS that you don't care about (and are processing).
  • GPS is super expensive uses satellites (more accurate, more battery).
  • Cell network provider uses Wifi and cell towers (less accurate, but less battery).
  • Passive provider is most battery efficient -- if someone else asked for GPS you get the most recent fetched location.
  • Set priority on your location requests.
  • Activity recognition to throttle/adjust to movements of the users.
  • Fused location provider simplifies all the request types (needs Google play services).
  • Spaces for different types of allocations with a set size.
  • Use the heap tool, create a blank activity to transition into, and force a garbage collection event.
  • Allocation Tracker tool to look at allocations which shows the order and where allocated.
  • Killing them off or not using are key to good performance.
  • Don't use a service to listen to and respond to events. Don't use it to poll the server.
  • Use async things instead of incurring the cost of services.
  • Don't let services live longer than they are needed.
  • Started services are alive until stopped. Bound service stays around until all are unbound.
  • Bundling/batching is fine for transient data, but when you want to make sure that the event goes through -- use a persistent store.
  • Can use a content provider to store pending requests. Query and then send.
  • SyncAdapter: You manage when to send the transfers -- if the radio isn't on you should skip. He later seems to contradict that statement.
  • Can use upload only flag to rate limit client initiated transferred.
  • Network trickles are probably too often -- only use in the foreground and reduce frequency.
  • Does this work well in low network conditions? How do I make sure that the messages are received on the client?
  • "Messages are queued if device isn't connected"
  • Sends plain text or JSON payloads. Can that be minimized?
  • collapse_key: Only one message when the device becomes active (no guarantee that it's the most recent) Best used to tell the app that there's something new to fetch (instead of it being the payload).
  • time_to_live: Default is 4 weeks, can make it shorter.
  • Each payload can be up to 4K of data. Key value pairs delivered via intent bundle.
  • When sending a payload, don't collapse. Limit of 100 messages.
  • Delivery order not guaranteed. Need to manage which one is the best/right one.
  • Good to use payloads for notifications to display. Also embed a sync tickle to get more data?
  • When you receive a sync tickle -- start the sync adapter (preferably bundled)
@umesh0492
Copy link

awesome 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment