We have had the same performance issues, we solved it by changing the following;
In function finish, declare a local var
lc_rows tp_rows;
See changes below
..
‘;
    add1xml( t_excel, ‘xl/theme/theme1.xml’, t_xxx );
    for s in 1 .. workbook.sheets.count()
    loop
      t_col_min := 16384;
      t_col_max := 1;
   /* vvvvvv CHANGED vvvvvvv */
      — t_row_ind := workbook.sheets( s ).rows.first();
      lc_rows := workbook.sheets( s ).rows;
   /*   while t_row_ind is not null
      loop
        t_col_min := least( t_col_min, workbook.sheets( s ).rows( t_row_ind ).first() );
        t_col_max := greatest( t_col_max, workbook.sheets( s ).rows( t_row_ind ).last() );
        t_row_ind := workbook.sheets( s ).rows.next( t_row_ind );
      end loop;
	*/
      t_row_ind := lc_rows.first();
      loop
       exit when t_row_ind is null;
        t_col_min := least( t_col_min, lc_rows( t_row_ind ).first () );
        t_col_max := greatest( t_col_max, lc_rows( t_row_ind ).last() );
        t_row_ind := lc_rows.next( t_row_ind );
      end loop;
   /* ^^^^^^ CHANGED ^^^^^^^ */
..
..
..
   /* vvvvvv CHANGED vvvvvvv */
   /*
      t_xxx := t_xxx || ”;
      t_row_ind := workbook.sheets( s ).rows.first();
      t_tmp := null;
      while t_row_ind is not null
      loop
        t_tmp :=  t_tmp || ”;
        t_len := length( t_tmp );
        t_col_ind := workbook.sheets( s ).rows( t_row_ind ).first();
        while t_col_ind is not null
        loop
          t_cell := ”
                 || to_char( workbook.sheets( s ).rows( t_row_ind )( t_col_ind ).value, ‘TM9′, ‘NLS_NUMERIC_CHARACTERS=.,’ )
                 || ”;
          if t_len > 32000
          then
            dbms_lob.writeappend( t_xxx, t_len, t_tmp );
            t_tmp := null;
            t_len := 0;
          end if;
          t_tmp :=  t_tmp || t_cell;
          t_len := t_len + length( t_cell );
          t_col_ind := workbook.sheets( s ).rows( t_row_ind ).next( t_col_ind );
        end loop;
        t_tmp :=  t_tmp || ”;
        t_row_ind := workbook.sheets( s ).rows.next( t_row_ind );
      end loop;
   */
/* New */
      t_xxx := t_xxx || ”;
      t_row_ind := lc_rows.first();
      t_tmp := null;
      while t_row_ind is not null
      loop
        t_tmp :=  t_tmp || ”;
        t_len := length( t_tmp );
        t_col_ind := lc_rows( t_row_ind ).first();
        while t_col_ind is not null
        loop
          t_cell := ”
                 || to_char( lc_rows( t_row_ind )( t_col_ind ).value, ‘TM9′, ‘NLS_NUMERIC_CHARACTERS=.,’ )
                 || ”;
          if t_len > 32000
          then
            dbms_lob.writeappend( t_xxx, t_len, t_tmp );
            t_tmp := null;
            t_len := 0;
          end if;
          t_tmp :=  t_tmp || t_cell;
          t_len := t_len + length( t_cell );
          t_col_ind := lc_rows( t_row_ind ).next( t_col_ind );
        end loop;
        t_tmp :=  t_tmp || ”;
        t_row_ind := lc_rows.next( t_row_ind );
      end loop;
/* ^^^^^^ CHANGED ^^^^^^^ */
Another change was made in procedure clear_workbook;
  procedure clear_workbook
  is
    t_row_ind    pls_integer;
    t_clear_rows tp_rows;
  begin
    for s in 1 .. workbook.sheets.count()
    loop
      workbook.sheets( s ).rows := t_clear_rows;
/*
      t_row_ind := workbook.sheets( s ).rows.first();
      while t_row_ind is not null
      loop
        workbook.sheets( s ).rows( t_row_ind ).delete();
        t_row_ind := workbook.sheets( s ).rows.next( t_row_ind );
      end loop;
*/
      workbook.sheets( s ).rows.delete();
      ..
Hope this will help.