How to debug performance issues?

I have a simple number keyboard that is taking over a 0.5s to render. This 20 buttons with labels on a panel of 272x337 pixels. Processor is a STM32F412 running at 96MHz with two frame buffers of 272x80 pixels. Display is 272x480 RGB888 with an 8 bit parallel if. Sending a buffer to the display takes around 6ms but this is using DMA with the lv_disp_flush_ready() being called as soon as the DMA is set up so writing to the display should not be holding up LVGL.
No RTOS, I am calling lv_timer_handler_run_in_period(5); from a main() while(1) loop. Also lv_tick_inc(1); from systick (which I have checked is running at 1ms).

To try to find out why the render is taking so long I have simplified things to a single white panel, no other objects. See code below.
I am then toggling the ui_PanelInf LV_OBJ_FLAG_HIDDEN every second to check performance. Even with this simple panel it is taking quite a long time.
If I time how long it takes (max) to run lv_timer_handler_run_in_period(5) in main I get 44ms.
If I check the time in monitor_callback() I get time = 1001 and px = 49530.
Using a 'scope to see the dma transfers I see two blocks taking about 6ms which are approx 10ms apart. From the scope trace it is hard to be certain how much time is spent rendering but it would appear it looks like have the panel per buffer. so, at a guess, around 32ms minimum. So the 44ms taking in lv_timer_handler() could well be the render time. But then why is the monitor callback reporting 1001ms? The number of pixels roughly match what I expect but the time does not.

Have I done something stupid? Any pointers on how to find where the time is going to?

btw. A secondary question: It would appear that lvgl will render the whole display (where necessary) in one call to lv_timer_handler(). Is this correct? It would be ok if it was taking a few 10s of ms to do it but when it takes over 500ms to render my keyboard this blocking causes a big problem for other housekeeping tasks. I could solve this by using an RTOS but would rather not if there is another way.

#define UI_WIDTH  272             // UI is portrait
#define UI_HEIGHT 480
#define FRAME_BUFF_LINES (UI_HEIGHT / 6) // warning, buff size has to stay under 16 bits or dma will fail.
static lv_color_t buf0[UI_WIDTH * FRAME_BUFF_LINES];
static lv_color_t buf1[UI_WIDTH * FRAME_BUFF_LINES];

void ui_init(void)
{
  lv_init();
  lv_disp_draw_buf_init(&draw_buf, buf0, buf1, UI_WIDTH * FRAME_BUFF_LINES);
  lv_disp_drv_init(&disp_drv);          /*Basic initialization*/
  disp_drv.flush_cb = my_disp_flush;    /*Set your driver function*/
  disp_drv.monitor_cb = monitor_callback;
  disp_drv.draw_buf = &draw_buf;        /*Assign the buffer to the display*/
  disp_drv.hor_res = UI_WIDTH;          /*Set the horizontal resolution of the display*/
  disp_drv.ver_res = UI_HEIGHT;         /*Set the vertical resolution of the display*/
  disp = lv_disp_drv_register(&disp_drv);      /*Finally register the driver*/

  lv_indev_drv_init(&indev_drv);        // now register the touch reading
  indev_drv.read_cb = touchpad_read;
  indev_drv.type = LV_INDEV_TYPE_POINTER;
  lv_indev_drv_register(&indev_drv);

  lv_disp_t * dispp = lv_disp_get_default();  // And finally create and display the main screen

  lv_theme_t * theme = lv_theme_default_init(dispp, primary_colour, lv_palette_main(LV_PALETTE_RED),
      false, LV_FONT_DEFAULT);

  lv_disp_set_theme(dispp, theme);
  ui_Screen1_screen_init();
  lv_disp_load_scr(ui_Screen1);
}
void ui_Screen1_screen_init(void)
{
    ui_Screen1 = lv_obj_create(NULL);
    lv_obj_clear_flag(ui_Screen1, LV_OBJ_FLAG_SCROLLABLE);      /// Flags
    lv_obj_set_style_bg_color(ui_Screen1, lv_color_hex(0x000000), LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_bg_opa(ui_Screen1, 255, LV_PART_MAIN | LV_STATE_DEFAULT);

    ui_test_Panel();
}
void ui_test_Panel()
{
  ui_PanelInf = lv_obj_create(ui_Screen1);
  lv_obj_set_width(ui_PanelInf, 244);
  lv_obj_set_height(ui_PanelInf, 185);
  lv_obj_set_x(ui_PanelInf, 0);
  lv_obj_set_y(ui_PanelInf, -85);
  lv_obj_set_align(ui_PanelInf, LV_ALIGN_BOTTOM_MID);
  lv_obj_clear_flag(ui_PanelInf, LV_OBJ_FLAG_SCROLLABLE);
}

I would check out this

which has a link to this