bleak: DBus backend high CPU usage and it grows over time

  • bleak version: 0.11.0
  • Python version: 3.7.9
  • Operating System: OpenWrt 19.07
  • BlueZ version (bluetoothctl -v) in case of Linux: 5.50

Description

I’m using bleak to run scanning devices and connect to some other devices. When I start my application it consumes high CPU percent but it is affordable. About 30-60% of the 800MHz device. And my application is responsive at the start so it is affordable.

After working for 10-20 hours CPU usage raising and it could take 95-100% all the time. The problem It that it leads to timeout exceptions while tasks don’t get their CPU time.

What I Did

  1. I restarted bluetoothd to flush caches or so, it didn’t help
  2. I tried to investigate the source and monitored the number of tasks that are running. But the number of tasks is constant in general. (Some tasks appeared for connected devices and then they are stopped).

Actually, I’m empty of ideas how I can stop this growing CPU usage. What else can I check to find out the root of the problem?

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 16 (9 by maintainers)

Commits related to this issue

Most upvoted comments

https://github.com/igo95862/python-sdbus/ looks interesting as well.

Thanks for all of the logs. I have a new theory about what is going on. BlueZ caches information on each device that it sees where a device is identified by its Bluetooth address. However, many Bluetooth Low Energy devices use random addresses that change frequently. So a huge cache of devices builds up in BlueZ, even if there is only one physical device.

Each time we start and stop scanning or connect to a client, we create an new D-Bus connection and call org.freedesktop.DBus.ObjectManager.GetManagedObjects. In your 2nd log (the one with lower CPU usage), the response to this is 1158 lines long. Compared to the 1st log where the response is 53170 lines long, it is easy to see why it would be using significantly more CPU (it is processing >45x the amount of data).

So, I think the solution will be to maintain a single D-Bus bus connection for monitoring D-Bus objects for the lifetime of a Bleak program. However, BleakClient will still need to have it’s own bus connection for calling the Connect method to avoid https://github.com/hbldh/bleak/issues/472#issuecomment-796330894.

I think it would also be worthwhile raising an issue with BlueZ to see if there is a way for it to not cache devices with random addresses.

What happens if you rewrite the loop like this?


async def start():
    async with BleakScanner(scanning_mode="passive") as scanner:
        scanner.register_detection_callback(
            device_detection_callback,
        )
        while True:
            await aio.sleep(3)
            await scanner.stop()
            print("New devices: ", scanner.discovered_devices)
            await aio.sleep(1)
            await scanner.start()