PERF: refactor string construction benchmark
State: closed

- [ ] closes #xxxx (Replace xxxx with the GitHub issue number)
- [ ] [Tests added and passed](https://pandas.pydata.org/pandas-docs/dev/development/contributing_codebase.html#writing-tests) if fixing a bug or adding a new feature
- [x] All [code checks passed](https://pandas.pydata.org/pandas-docs/dev/development/contributing_codebase.html#pre-commit).
- [ ] Added [type annotations](https://pandas.pydata.org/pandas-docs/dev/development/contributing_codebase.html#type-hints) to new arguments/methods/functions.
- [ ] Added an entry in the latest `doc/source/whatsnew/vX.X.X.rst` file if fixing a bug or adding a new feature.

For `asv` `peakmem` benchmarks, the memory cost of the setup function is included in the benchmark result. The way this benchmark is currently written, the memory usage is dominated by constructing `series_cat_arr`, so the memory benchmark results aren't very useful for `Series` and `DataFrame`. I also added `string[pyarrow]` to the benchmark because why not?

The results before the refactor:

<details>

```
[ 8.33%] ··· strings.Construction.peakmem_cat_series_construction
                                ok
[ 8.33%] ··· ======== ======
              dtype         
             -------- ------
               str     329M 
              string   313M 
             ======== ======

[16.67%] ··· strings.Construction.peakmem_frame_construction
                                     ok
[16.67%] ··· ======== ======
              dtype         
             -------- ------
               str     313M 
              string   313M 
             ======== ======

[25.00%] ··· strings.Construction.peakmem_series_construction
                                    ok
[25.00%] ··· ======== ======
              dtype         
             -------- ------
               str     313M 
              string   313M 
             ======== ======

[33.33%] ··· strings.Construction.time_cat_series_construction
                                   ok
[33.33%] ··· ======== ==========
              dtype             
             -------- ----------
               str     213±0ms  
              string   43.1±0ms 
             ======== ==========

[41.67%] ··· strings.Construction.time_frame_construction
                                        ok
[41.67%] ··· ======== ==========
              dtype             
             -------- ----------
               str     37.9±0ms 
              string   54.5±0ms 
             ======== ==========

[50.00%] ··· strings.Construction.time_series_construction
                                       ok
[50.00%] ··· ======== ==========
              dtype             
             -------- ----------
               str     38.1±0ms 
              string   39.5±0ms 
             ======== ==========
```

</details>

And after:

<details>

```
[25.00%] ··· strings.Construction.peakmem_construction
                                           ok
[25.00%] ··· ==================== ====== ================ =================
             --                                     dtype                  
             -------------------- -----------------------------------------
                   pd_type         str    string[python]   string[pyarrow] 
             ==================== ====== ================ =================
                    series         310M        310M              316M      
                    frame          310M        310M              316M      
              categorical_series   327M        313M              319M      
             ==================== ====== ================ =================

[50.00%] ··· strings.Construction.time_construction
                                              ok
[50.00%] ··· ==================== ========== ================ =================
             --                                       dtype                    
             -------------------- ---------------------------------------------
                   pd_type           str      string[python]   string[pyarrow] 
             ==================== ========== ================ =================
                    series         39.3±0ms      37.6±0ms          48.9±0ms    
                    frame          40.0±0ms      41.7±0ms          56.4±0ms    
              categorical_series   215±0ms       44.7±0ms          57.0±0ms    
             ==================== ========== ================ =================
```

</details>

Note the different, lower, peak memory usages. I also find it a bit easier to compare results as two parameterized benchmarks.

Labels:
name: Benchmark
description: Performance (ASV) benchmarks

Comments:
In principle we don’t but IMO it makes the timing benchmarks more fair because it avoids a copy to numpy’s string dtype inside pandas. I have a version of this benchmark with the new string dtype I’ve been working on and avoiding that copy is *substantially* faster there.
Thanks @ngoldbaum