Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PERF: Regressions since 0.20.3 #17861

Closed
TomAugspurger opened this issue Oct 13, 2017 · 33 comments
Closed

PERF: Regressions since 0.20.3 #17861

TomAugspurger opened this issue Oct 13, 2017 · 33 comments
Labels
Performance Memory or execution speed performance
Milestone

Comments

@TomAugspurger
Copy link
Contributor

These are fairly reproducible on my machine:

       before           after         ratio
     [eac4d3f7]       [92db5c9c]
+           396μs            746μs     1.88  inference.DtypeInfer.time_uint32
+     2.63±0.02ms       3.93±0.1ms     1.49  indexing.IndexingMethods.time_take_dtindex
+     2.64±0.06ms      3.83±0.06ms     1.45  indexing.IndexingMethods.time_take_intindex
       before           after         ratio
     [eac4d3f7]       [92db5c9c]
+     1.43±0.01ms      1.74±0.07ms     1.22  frame_ctor.FrameConstructorDTIndexFromOffsets.time_frame_ctor('BDay', 1)
+     1.56±0.02ms      1.74±0.07ms     1.12  frame_ctor.FrameConstructorDTIndexFromOffsets.time_frame_ctor('MonthBegin', 2)
+          56.0ms           61.8ms     1.10  frame_ctor.FrameConstructorDTIndexFromOffsets.time_frame_ctor('FY5253Quarter_2', 2)
@TomAugspurger TomAugspurger added the Performance Memory or execution speed performance label Oct 13, 2017
@TomAugspurger TomAugspurger added this to the 0.21.0 milestone Oct 13, 2017
@jreback
Copy link
Contributor

jreback commented Oct 14, 2017

cc @jbrockmendel if u have any ideas here

@jbrockmendel
Copy link
Member

I'll take a look at this.

@jbrockmendel
Copy link
Member

Best guess is the change in _to_i8 (previously in _libs.index, now in tslib). Old:

cdef inline _to_i8(object val):
    cdef pandas_datetimestruct dts
    try:
        return val.value
    except AttributeError:
        if util.is_datetime64_object(val):
            return get_datetime64_value(val)
        elif PyDateTime_Check(val):
            tzinfo = getattr(val, 'tzinfo', None)
            # Save the original date value so we can get the utcoffset from it.
            ival = _pydatetime_to_dts(val, &dts)
            if tzinfo is not None and not is_utc(tzinfo):
                offset = get_utcoffset(tzinfo, val)
                ival -= tslib._delta_to_nanoseconds(offset)
            return ival
        return val

New:

cdef inline _to_i8(object val):
    cdef pandas_datetimestruct dts
    try:
        return val.value
    except AttributeError:
        if is_datetime64_object(val):
            return get_datetime64_value(val)
        elif PyDateTime_Check(val):
            return Timestamp(val).value
        return val

@jbrockmendel
Copy link
Member

Hmm in %timeit reverting this makes a pretty big difference for the ind.get_loc(0) bench, but pretty small (though at least in the right direction) differences for time_take_dtindex and time_take_intindex

@jbrockmendel
Copy link
Member

Does asv have something analogous to git bisect?

@jorisvandenbossche
Copy link
Member

@TomAugspurger TomAugspurger mentioned this issue Oct 23, 2017
64 tasks
@TomAugspurger
Copy link
Contributor Author

Sorry, those commit hashes in the original post look entirely incorrect... Let me rerun them.

@TomAugspurger
Copy link
Contributor Author

TomAugspurger commented Oct 25, 2017

Updated:

       before           after         ratio
       [888c4ec3]       [36c309ed]
!     4.01±0.02ms           failed      n/a  frame_ctor.FrameConstructorDTIndexFromOffsets.time_frame_ctor('LastWeekOfMonth', 1)
!     4.39±0.01ms           failed      n/a  frame_ctor.FrameConstructorDTIndexFromOffsets.time_frame_ctor('LastWeekOfMonth', 2)
!      9.17±0.1ms           failed      n/a  frame_methods.Formatting.time_frame_repr_wide
!      19.7±0.2ms           failed      n/a  frame_methods.Formatting.time_html_repr_trunc_mi
!      14.4±0.2ms           failed      n/a  frame_methods.Formatting.time_html_repr_trunc_si
!      10.8±0.1ms           failed      n/a  frame_methods.Formatting.time_repr_tall
!         117±2ms           failed      n/a  frame_methods.Formatting.time_to_html_mixed
!      14.1±0.1ms           failed      n/a  frame_methods.Formatting.time_to_string_floats
+      10.3±0.5ms            4.83s   469.35  inference.DtypeInfer.time_timedelta64_2
+     8.94±0.09ms            3.03s   339.45  inference.DtypeInfer.time_datetime64
+      29.8±0.4ms            5.99s   201.19  binary_ops.Timeseries.time_timestamp_ops_diff2
+        80.7±1ms            9.27s   114.89  binary_ops.TimeseriesTZ.time_timestamp_ops_diff2
+     3.36±0.03ms          278±2ms    82.71  timeseries.SeriesArithmetic.time_add_offset_delta
+      60.2±0.4ms            3.91s    64.91  inference.DtypeInfer.time_timedelta64_1
+      9.64±0.2ms          297±5ms    30.83  timeseries.SeriesArithmetic.time_add_offset_fast
+     6.18±0.09ms          122±1ms    19.77  categoricals.Categoricals3.time_rank_string_cat
+      36.6±0.4ms          576±1ms    15.75  packers.packers_read_stata.time_packers_read_stata
+     45.8±0.01ms            616ms    13.44  packers.packers_read_stata_with_validation.time_packers_read_stata_with_validation
+      28.5±0.2ms          308±2ms    10.84  packers.STATA.time_write_stata
+      40.5±0.4ms        323±0.9ms     7.97  packers.STATA.time_write_stata_with_validation
+      34.1±0.4ms          107±1ms     3.15  join_merge.Align.time_series_align_int64_index
+        631±10μs      1.51±0.01ms     2.39  indexing.Int64Indexing.time_getitem_array
+     7.13±0.04ms      16.4±0.09ms     2.30  timeseries.DatetimeIndex.time_infer_freq_none
+     3.62±0.05ms       7.34±0.1ms     2.03  indexing.Int64Indexing.time_getitem_lists
+     2.44±0.04μs      4.25±0.05μs     1.74  indexing.DataFrameIndexing.time_get_value
+         285±6μs         490±10μs     1.72  indexing.Int64Indexing.time_getitem_list_like
+      19.2±0.1ms       30.8±0.8ms     1.60  sparse.sparse_array_constructor.time_sparse_array_constructor_object_non_nan_fill_value_1percent
+      32.2±0.4ms       48.7±0.1ms     1.51  sparse.sparse_array_constructor.time_sparse_array_constructor_object_non_nan_fill_value_10percent
+     2.47±0.03ms      3.72±0.04ms     1.51  indexing.IndexingMethods.time_take_dtindex
+     2.48±0.07ms      3.73±0.03ms     1.50  indexing.IndexingMethods.time_take_intindex
+      6.12±0.1ms      9.04±0.05ms     1.48  binary_ops.Ops2.time_frame_int_div_by_zero
+     5.33±0.01ms      7.65±0.01ms     1.43  timeseries.DatetimeIndex.time_infer_freq_business
+        564±20ms          792±7ms     1.40  timeseries.SeriesArithmetic.time_add_offset_slow
+     2.95±0.09ms      4.05±0.03ms     1.37  strings.StringMethods.time_get
+     2.68±0.02ms      3.66±0.06ms     1.37  period.Algorithms.time_value_counts_pseries
+     2.09±0.03ms      2.87±0.02ms     1.37  period.Algorithms.time_drop_duplicates_pseries
+     6.84±0.07μs       8.89±0.1μs     1.30  timestamp.TimestampOps.time_replace_across_dst
+         252±2ms          322±5ms     1.28  rolling.SeriesRolling.time_rolling_quantile_median_l
+      7.91±0.1μs       10.1±0.1μs     1.28  timestamp.TimestampOps.time_replace_tz
+       252±0.6ms          322±1ms     1.28  rolling.DataframeRolling.time_rolling_quantile_median_l
+     1.25±0.01ms      1.58±0.01ms     1.26  categoricals.Categoricals.time_constructor_datetimes_with_nat
+         1.30±0s            1.61s     1.24  groupby.GroupBySuite.time_unique('float', 10000)
+      10.1±0.2μs       12.5±0.2μs     1.23  timestamp.TimestampProperties.time_is_quarter_end
+         842±4ms          1.02±0s     1.22  groupby.GroupBySuite.time_unique('int', 10000)
+         113±1ms          135±1ms     1.19  rolling.SeriesRolling.time_rolling_quantile_median
+         111±1ms          132±2ms     1.19  rolling.DataframeRolling.time_rolling_quantile_median
+     3.17±0.04ms      3.77±0.05ms     1.19  index_object.SetOperations.time_datetime_difference
+      9.66±0.1ms       11.4±0.1ms     1.18  groupby.GroupBySuite.time_unique('int', 100)
+      35.5±0.5μs       41.5±0.4μs     1.17  indexing.IntervalIndexing.time_getitem_scalar
+      14.5±0.2ms       16.9±0.4ms     1.17  groupby.GroupBySuite.time_unique('float', 100)
+      59.9±0.3ms       69.8±0.3ms     1.17  hdfstore_bench.HDF5.time_write_store_table
+        34.7±1ms       40.3±0.5ms     1.16  strings.StringMethods.time_join_split_expand
+     3.98±0.05ms      4.59±0.05ms     1.15  groupby.Transform.time_transform_ufunc
+         227±2μs          261±6μs     1.15  indexing.MultiIndexing.time_series_xs_mi_ix
+      10.5±0.1μs       12.1±0.2μs     1.15  indexing.Int64Indexing.time_iloc_scalar
+     1.68±0.01ms         1.93±0ms     1.14  indexing.MultiIndexing.time_multiindex_get_indexer
+         251±4μs          287±2μs     1.14  indexing.MultiIndexing.time_multiindex_large_get_loc
+     6.53±0.03μs      7.47±0.07μs     1.14  timestamp.TimestampOps.time_replace_None
+      41.3±0.7μs       46.8±0.5μs     1.13  indexing.Int64Indexing.time_loc_scalar
+      84.1±0.7μs       94.4±0.6μs     1.12  series_methods.series_clip.time_series_dropna_datetime
+           508ms            568ms     1.12  groupby.groupby_multi_index.time_groupby_multi_index
+       206±0.8ms          231±2ms     1.12  timeseries.ToDatetime.time_iso8601_tz_spaceformat
+         199±2ms        221±0.5ms     1.12  packers.Packers.time_packers_read_csv
+         606±3μs          674±5μs     1.11  groupby.GroupBySuite.time_value_counts('float', 100)
+       265±0.9μs          294±3μs     1.11  indexing.MultiIndexing.time_frame_xs_mi_ix
+      8.49±0.1ms         9.39±1ms     1.11  eval.Eval.time_mult('numexpr', 1)
+     8.07±0.04μs      8.91±0.09μs     1.10  timeseries.DatetimeIndex.time_timestamp_tzinfo_cons
+         209±2ms          231±3ms     1.10  groupby.GroupBySuite.time_describe('float', 100)
+          73.8ms           81.4ms     1.10  packers.JSON.time_write_json
+      58.2±0.7μs       64.0±0.7μs     1.10  indexing.IntervalIndexing.time_loc_scalar
+      31.3±0.2μs       34.4±0.6μs     1.10  indexing.Int64Indexing.time_ix_scalar

verifying for correctness and then I'll start digging into them.

@TomAugspurger
Copy link
Contributor Author

TomAugspurger commented Oct 25, 2017

+      10.3±0.5ms            4.83s   469.35  inference.DtypeInfer.time_timedelta64_2
+     8.94±0.09ms            3.03s   339.45  inference.DtypeInfer.time_datetime64

are real. _maybe_box_datetimelike looks suspicious (this is the RC):

ncalls tottime percall cumtime percall filename:lineno(function)
2000000 6.369 3.185e-06 6.57 3.285e-06 common.py:170(_maybe_box_datetimelike)
2 0.6152 0.3076 7.185 3.593 base.py:813()
2000723/2000456 0.2013 1.006e-07 0.203 1.015e-07 ~:0()

http://pandas.pydata.org/speed/pandas/#inference.DtypeInfer.time_datetime64 points to ~ eef810ef (cc @jreback)

@TomAugspurger
Copy link
Contributor Author

TomAugspurger commented Oct 25, 2017

DtypeInfer:

+      10.3±0.4ms            4.78s   464.27  inference.DtypeInfer.time_timedelta64_2
+     8.71±0.07ms            2.93s   336.02  inference.DtypeInfer.time_datetime64
+        63.4±2ms            3.84s    60.54  inference.DtypeInfer.time_timedelta64_1

SeriesArthmetic.time_add_offset*

560±20ms       before           after         ratio
     [888c4ec3]       [36c309ed]
+     3.38±0.08ms          298±9ms    87.90  timeseries.SeriesArithmetic.time_add_offset_delta
+     10.00±0.3ms          294±3ms    29.37  timeseries.SeriesArithmetic.time_add_offset_fast
+        560±20ms          803±2ms     1.43  timeseries.SeriesArithmetic.time_add_offset_slow

These are handled by #17980

@TomAugspurger
Copy link
Contributor Author

TomAugspurger commented Oct 25, 2017

categoricals.Categoricals3.time_rank_string_cat_ordered

5.12±0.08ms       before           after         ratio
     [888c4ec3]       [36c309ed]
+      7.22±0.5ms          139±6ms    19.25  categoricals.Categoricals3.time_rank_string_cat

Seems like this is ranking the objects, instead of codes.

This is handled by #17982

@TomAugspurger
Copy link
Contributor Author

TomAugspurger commented Oct 25, 2017

packers.*stata.*

46.1±0.01ms       before           after         ratio
     [888c4ec3]       [36c309ed]
+      36.5±0.3ms          601±6ms    16.47  packers.packers_read_stata.time_packers_read_stata
+     46.1±0.01ms            575ms    12.48  packers.packers_read_stata_with_validation.time_packers_read_stata_with_validation
+      30.2±0.7ms            346ms    11.48  packers.STATA.time_write_stata
+          42.5ms            339ms     7.96  packers.STATA.time_write_stata_with_validation

Fixed by #17980

@TomAugspurger
Copy link
Contributor Author

TomAugspurger commented Oct 25, 2017

join_merge:

36.1±0.7ms       before           after         ratio
     [888c4ec3]       [36c309ed]
+      36.1±0.7ms          112±4ms     3.09  join_merge.Align.time_series_align_int64_index

Ah dang, http://pandas.pydata.org/speed/pandas/#join_merge.Align.time_series_align_int64_index points to the import delay PR: 2310faa1

I think something strange is going on w/ the benchmark... On 0.20.3 and 0.21.0rc1, I'm seeing the numexpr import affecting the benchmark time. The first run is always ~120ms. Subsequent runs are ~25-30ms. I'l come back to this later.

@TomAugspurger
Copy link
Contributor Author

TomAugspurger commented Oct 25, 2017

indexing.Int64Indexing.time_getitem.*

[100.00%] ··· Running indexing.Int64Indexing.time_getitem_slice                                                                                   46.8±0.3μs       before           after         ratio
     [888c4ec3]       [36c309ed]
+         622±7μs      1.57±0.02ms     2.53  indexing.Int64Indexing.time_getitem_array
+     3.73±0.07ms       7.46±0.1ms     2.00  indexing.Int64Indexing.time_getitem_lists
+         301±7μs          492±3μs     1.63  indexing.Int64Indexing.time_getitem_list_like

Looks like #17295 for this one http://pandas.pydata.org/speed/pandas/#join_merge.Align.time_series_align_int64_index

cc @jreback not sure if there's anything to be done there.

@TomAugspurger
Copy link
Contributor Author

TomAugspurger commented Oct 25, 2017

indexing.DataFrameIndexing.time_get_value

394±2ms       before           after         ratio
     [888c4ec3]       [36c309ed]
+     2.49±0.03μs       4.40±0.3μs     1.77  indexing.DataFrameIndexing.time_get_value

I believe this was due to 3fae8dd

@TomAugspurger
Copy link
Contributor Author

-b timeseries.DatetimeIndex.time_infer_

            before           after         ratio
     [888c4ec3]       [36c309ed]
+      8.68±0.7ms      16.2±0.07ms     1.87  timeseries.DatetimeIndex.time_infer_freq_none
+      5.53±0.2ms      7.80±0.05ms     1.41  timeseries.DatetimeIndex.time_infer_freq_business

@TomAugspurger
Copy link
Contributor Author

sparse.sparse_array_constructor.time_sparse_array_constructor_object_non_nan_fill_value_

+      32.4±0.2ms         52.9±3ms     1.63  sparse.sparse_array_constructor.time_sparse_array_constructor_object_non_nan_fill_value_10percent
+     19.2±0.07ms       29.8±0.2ms     1.55  sparse.sparse_array_constructor.time_sparse_array_constructor_object_non_nan_fill_value_1percent

@TomAugspurger
Copy link
Contributor Author

indexing.IndexingMethods.time_take_d

+     2.49±0.04ms      3.89±0.06ms     1.56  indexing.IndexingMethods.time_take_intindex
+     2.48±0.04ms      3.84±0.05ms     1.55  indexing.IndexingMethods.time_take_dtindex

@TomAugspurger
Copy link
Contributor Author

+     2.16±0.03ms      3.00±0.08ms     1.39  period.Algorithms.time_drop_duplicates_pseries
+     2.77±0.05ms      3.41±0.03ms     1.23  period.Algorithms.time_value_counts_pseries

@jbrockmendel
Copy link
Member

For morale purposes: is there any good news?

@TomAugspurger
Copy link
Contributor Author

TomAugspurger commented Oct 25, 2017

:) Yeah there were quite a few:

-         148±2ms          135±2ms     0.91  gil.nogil_rolling_algos_slow.time_nogil_rolling_median
-     1.77±0.01ms      1.61±0.01ms     0.91  frame_ctor.FrameConstructorDTIndexFromOffsets.time_frame_ctor('BQuarterBegin', 1)
-        68.4±1ms       62.1±0.4ms     0.91  hdfstore_bench.HDF5.time_write_store_table_mixed
-     1.51±0.05ms      1.37±0.02ms     0.91  frame_ctor.FrameConstructorDTIndexFromOffsets.time_frame_ctor('Week', 1)
-         359±6ms          325±2ms     0.90  io_bench.read_json_lines.time_read_json_lines
-      11.5±0.3μs      10.4±0.05μs     0.90  period.Algorithms.time_drop_duplicates_pindex
-     3.85±0.04ms      3.48±0.03ms     0.90  stat_ops.stat_ops_level_series_sum_multiple.time_stat_ops_level_series_sum_multiple
-         104±1μs       93.8±0.7μs     0.90  frame_ctor.frame_get_numeric_data.time_frame_get_numeric_data
-     1.73±0.04ms      1.56±0.01ms     0.90  frame_ctor.FrameConstructorDTIndexFromOffsets.time_frame_ctor('QuarterEnd', 2)
-       145±0.9ms          131±1ms     0.90  inference.to_numeric_downcast.time_downcast('string-float', None)
-     1.79±0.02ms      1.61±0.01ms     0.90  frame_ctor.FrameConstructorDTIndexFromOffsets.time_frame_ctor('BMonthBegin', 2)
-     4.32±0.04ms      3.89±0.03ms     0.90  timeseries.ToDatetime.time_iso8601_format_no_sep
-     3.27±0.05ms      2.94±0.02ms     0.90  frame_ctor.FrameConstructorDTIndexFromOffsets.time_frame_ctor('FY5253_1', 1)
-     3.25±0.07ms      2.91±0.03ms     0.90  frame_ctor.FrameConstructorDTIndexFromOffsets.time_frame_ctor('FY5253_1', 2)
-     14.5±0.09ms      12.9±0.06ms     0.89  io_sql.ReadSQLTypes.time_float_read_table_sqlalchemy
-     9.26±0.08ms      8.25±0.02ms     0.89  inference.to_numeric.time_from_str_coerce
-      1.57±0.1ms      1.40±0.02ms     0.89  frame_ctor.FrameConstructorDTIndexFromOffsets.time_frame_ctor('BusinessDay', 1)
-     1.82±0.03ms      1.62±0.03ms     0.89  frame_ctor.FrameConstructorDTIndexFromOffsets.time_frame_ctor('BMonthBegin', 1)
-          17.2ms           15.2ms     0.89  frame_ctor.FrameConstructorDTIndexFromOffsets.time_frame_ctor('FY5253Quarter_1', 2)
-         330±1ms          293±4ms     0.89  replace.replace_convert.time_replace_series_timedelta
-           3.09s            2.74s     0.89  stat_ops.FrameOps.time_op('median', True, 'float', 1)
-      47.4±0.2ms       41.9±0.3ms     0.88  frame_ctor.FromDicts.time_frame_ctor_nested_dict_int64
-      46.8±0.4ms       41.2±0.5ms     0.88  frame_ctor.FromDicts.time_frame_ctor_nested_dict
-     1.18±0.02ms      1.04±0.01ms     0.88  indexing.DataFrameIndexing.time_loc_dups
-         114±4ms        100±0.6ms     0.88  frame_methods.Apply.time_apply_user_func
-     4.40±0.02ms      3.86±0.01ms     0.88  timeseries.ToDatetime.time_iso8601
-         331±3ms          290±4ms     0.88  replace.replace_convert.time_replace_series_timestamp
-     1.76±0.01ms      1.54±0.03ms     0.88  frame_ctor.FrameConstructorDTIndexFromOffsets.time_frame_ctor('BYearBegin', 2)
-        255±10μs          224±2μs     0.88  frame_methods.frame_boolean_row_select.time_frame_boolean_row_select
-     1.51±0.04ms      1.32±0.02ms     0.88  frame_ctor.FrameConstructorDTIndexFromOffsets.time_frame_ctor('YearEnd', 2)
-     1.81±0.03ms      1.59±0.03ms     0.88  frame_ctor.FrameConstructorDTIndexFromOffsets.time_frame_ctor('BQuarterBegin', 2)
-     1.74±0.02ms      1.52±0.02ms     0.87  frame_ctor.FrameConstructorDTIndexFromOffsets.time_frame_ctor('QuarterEnd', 1)
-        71.1±4μs       62.1±0.6μs     0.87  frame_methods.frame_xs_row.time_frame_xs_row
-     4.40±0.07ms      3.85±0.02ms     0.87  timeseries.ToDatetime.time_iso8601_format
-           6.20s            5.41s     0.87  groupby.GroupBySuite.time_mad('int', 10000)
-     4.40±0.05ms      3.83±0.01ms     0.87  timeseries.ToDatetime.time_iso8601_nosep
-     1.49±0.02ms      1.29±0.03ms     0.87  frame_ctor.FrameConstructorDTIndexFromOffsets.time_frame_ctor('YearEnd', 1)
-        92.5±2μs         80.2±2μs     0.87  period.Properties.time_end_time
-     1.50±0.02ms      1.30±0.02ms     0.86  groupby.groupby_categorical.time_groupby_ordered_sort
-     1.51±0.01ms      1.30±0.02ms     0.86  groupby.groupby_categorical.time_groupby_sort
-     2.00±0.04ms      1.73±0.01ms     0.86  frame_ctor.FrameConstructorDTIndexFromOffsets.time_frame_ctor('BusinessHour', 2)
-     1.77±0.05ms      1.52±0.03ms     0.86  frame_ctor.FrameConstructorDTIndexFromOffsets.time_frame_ctor('BQuarterEnd', 2)
-         544±5ms          468±2ms     0.86  replace.replace_convert.time_replace_frame_timestamp
-         543±4ms          465±3ms     0.86  replace.replace_convert.time_replace_frame_timedelta
-      7.00±0.1ms      6.00±0.06ms     0.86  timeseries.DatetimeAccessor.time_dt_accessor_normalize
-     2.38±0.03ms      2.03±0.03ms     0.86  frame_ctor.FrameConstructorDTIndexFromOffsets.time_frame_ctor('CustomBusinessHour', 1)
-         393±3μs          335±3μs     0.85  join_merge.Append.time_append_homogenous
-     1.82±0.06ms      1.55±0.04ms     0.85  frame_ctor.FrameConstructorDTIndexFromOffsets.time_frame_ctor('CDay', 2)
-     2.42±0.04ms      2.06±0.04ms     0.85  frame_ctor.FrameConstructorDTIndexFromOffsets.time_frame_ctor('CustomBusinessHour', 2)
-     1.54±0.01ms      1.29±0.02ms     0.84  frame_ctor.FrameConstructorDTIndexFromOffsets.time_frame_ctor('YearBegin', 1)
-     1.87±0.06ms      1.57±0.02ms     0.84  frame_ctor.FrameConstructorDTIndexFromOffsets.time_frame_ctor('BQuarterEnd', 1)
-         1.05±0s          873±2ms     0.83  groupby.groupby_frame_apply.time_groupby_frame_df_copy_function
-         421±2ms          347±4ms     0.83  groupby.groupby_frame_apply.time_groupby_frame_apply_df_copy_overhead
-         377±1μs          308±2μs     0.82  algorithms.Algorithms.time_match_strings
-          71.2ms           58.0ms     0.81  frame_ctor.FrameConstructorDTIndexFromOffsets.time_frame_ctor('FY5253Quarter_2', 2)
-         581±7μs        472±0.8μs     0.81  frame_methods.Iteration.time_iteritems_cached
-     1.69±0.04ms      1.35±0.01ms     0.80  frame_ctor.FrameConstructorDTIndexFromOffsets.time_frame_ctor('Easter', 2)
-      26.3±0.1ms       21.0±0.5ms     0.80  sparse.sparse_series_to_coo.time_sparse_series_to_coo
-          43.8ms           35.0ms     0.80  frame_ctor.FrameConstructorDTIndexFromOffsets.time_frame_ctor('FY5253Quarter_2', 1)
-           11.1s            8.85s     0.79  panel_methods.PanelMethods.time_pct_change_items
-      2.20±0.2ms      1.74±0.04ms     0.79  frame_ctor.FrameConstructorDTIndexFromOffsets.time_frame_ctor('BusinessHour', 1)
-      12.5±0.2μs      9.72±0.09μs     0.78  period.period_standard_indexing.time_get_loc
-         204±2μs        156±0.9μs     0.76  timeseries.Offsets.time_custom_bmonthend_incr
-      13.1±0.3ms       9.91±0.1ms     0.76  frame_ctor.FrameConstructorDTIndexFromOffsets.time_frame_ctor('FY5253_2', 1)
-      22.5±0.5ms       16.9±0.2ms     0.75  categoricals.Categoricals2.time_value_counts_dropna
-     2.96±0.02ms      2.21±0.05ms     0.75  frame_ctor.FrameConstructorDTIndexFromOffsets.time_frame_ctor('CBMonthBegin', 2)
-        966±10μs          717±7μs     0.74  join_merge.Append.time_append_mixed
-      1.85±0.1ms      1.37±0.01ms     0.74  frame_ctor.FrameConstructorDTIndexFromOffsets.time_frame_ctor('Easter', 1)
-      3.67±0.2ms      2.71±0.02ms     0.74  groupby.GroupBySuite.time_last('float', 10000)
-     4.56±0.07ms      3.37±0.05ms     0.74  frame_ctor.FrameConstructorDTIndexFromOffsets.time_frame_ctor('CBMonthEnd', 1)
-      13.7±0.2ms      10.1±0.05ms     0.73  frame_ctor.FrameConstructorDTIndexFromOffsets.time_frame_ctor('FY5253_2', 2)
-         848±9ns         620±10ns     0.73  timestamp.TimestampOps.time_to_pydatetime
-      4.72±0.2ms      3.45±0.08ms     0.73  frame_ctor.FrameConstructorDTIndexFromOffsets.time_frame_ctor('CBMonthEnd', 2)
-     2.55±0.07ms           1.86ms     0.73  inference.DtypeInfer.time_float64
-      20.4±0.3ms       14.6±0.3ms     0.72  categoricals.Categoricals2.time_value_counts
-      2.58±0.3ms           1.81ms     0.70  inference.DtypeInfer.time_int64
-      32.7±0.8ms       22.6±0.7ms     0.69  binary_ops.Ops.time_frame_comparison(False, 1)
-         272±6μs          187±6μs     0.69  timeseries.Offsets.time_custom_bmonthbegin_incr_n
-      16.1±0.1ms      11.0±0.05ms     0.68  groupby.groupby_categorical.time_groupby_ordered_nosort
-         256±6μs          174±2μs     0.68  timeseries.Offsets.time_custom_bmonthend_incr_n
-      57.7±0.6ms       38.5±0.7ms     0.67  join_merge.Concat.time_concat_small_frames
-     3.95±0.05ms      2.63±0.09ms     0.67  frame_ctor.FrameConstructorDTIndexFromOffsets.time_frame_ctor('CBMonthBegin', 1)
-     1.35±0.04ms         891±20μs     0.66  replace.replace_replacena.time_replace_replacena
-        32.5±2ms         21.4±1ms     0.66  binary_ops.Ops.time_frame_comparison(False, 'default')
-      10.7±0.1ms       6.98±0.1ms     0.65  groupby.groupby_categorical.time_groupby_nosort
-      3.68±0.2ms      2.39±0.03ms     0.65  frame_ctor.FrameConstructorDTIndexFromOffsets.time_frame_ctor('WeekOfMonth', 2)
-           8.77s            5.47s     0.62  panel_methods.PanelMethods.time_pct_change_minor
-         297±2μs          181±2μs     0.61  timeseries.Offsets.time_custom_bmonthend_decr_n
-           9.15s            5.54s     0.61  panel_methods.PanelMethods.time_pct_change_major
-     8.82±0.06ms      5.31±0.05ms     0.60  groupby.groupby_categorical.time_groupby_extra_cat_nosort
-      4.04±0.3ms      2.42±0.06ms     0.60  frame_ctor.FrameConstructorDTIndexFromOffsets.time_frame_ctor('WeekOfMonth', 1)
-     1.84±0.01μs      1.09±0.02μs     0.59  period.Properties.time_is_leap_year
-        67.0±1ms       39.4±0.1ms     0.59  eval.Eval.time_chained_cmp('python', 'all')
-      28.5±0.6ms       16.6±0.5ms     0.58  frame_methods.frame_fancy_lookup.time_frame_fancy_lookup_all
-      26.1±0.2μs       14.7±0.2μs     0.56  timeseries.Offsets.time_timeseries_year_incr
-           8.89y            5.00y     0.56  io_bench.read_json_lines.peakmem_read_json_lines
-         266±3μs          147±3μs     0.55  timeseries.Offsets.time_custom_bmonthbegin_decr_n
-     1.82±0.02μs      1.00±0.01μs     0.55  period.Properties.time_daysinmonth
-     1.82±0.03μs          977±8ns     0.54  period.Properties.time_year
-     1.80±0.03μs         959±10ns     0.53  period.Properties.time_second
-     1.80±0.01μs         950±10ns     0.53  period.Properties.time_dayofweek
-     1.83±0.01μs         956±10ns     0.52  period.Properties.time_dayofyear
-     1.82±0.02μs         948±30ns     0.52  period.PeriodProperties.time_hour
-     1.79±0.01μs          931±3ns     0.52  period.Properties.time_month
-     1.82±0.01μs          942±7ns     0.52  period.PeriodProperties.time_second
-     1.81±0.03μs         925±20ns     0.51  period.Properties.time_quarter
-     1.83±0.02μs         933±10ns     0.51  period.PeriodProperties.time_day
-     1.85±0.01μs         943±20ns     0.51  period.PeriodProperties.time_quarter
-     1.81±0.02μs         919±10ns     0.51  period.Properties.time_minute
-     1.90±0.03μs         965±10ns     0.51  period.PeriodProperties.time_year
-     1.85±0.02μs         936±20ns     0.51  period.PeriodProperties.time_month
-      22.6±0.3μs      11.4±0.07μs     0.50  timeseries.Offsets.time_timeseries_year_apply
-     1.85±0.03μs          929±5ns     0.50  period.Properties.time_day
-     2.00±0.05μs         999±10ns     0.50  period.Properties.time_week
-     1.90±0.02μs         939±10ns     0.49  period.Properties.time_qyear
-     1.90±0.02μs         930±10ns     0.49  period.PeriodProperties.time_minute
-     1.96±0.03μs         912±10ns     0.47  period.Properties.time_hour
-     15.2±0.07ms      6.96±0.05ms     0.46  binary_ops.Ops.time_frame_comparison(True, 'default')
-       321±0.8ms          143±1ms     0.44  sparse.sparse_series_to_frame.time_sparse_series_to_frame
-      49.4±0.4ms       21.3±0.2ms     0.43  eval.Eval.time_chained_cmp('python', 1)
-     8.61±0.01ms      3.68±0.04ms     0.43  categoricals.Categoricals.time_union
-     11.1±0.05ms      2.74±0.06ms     0.25  binary_ops.Ops.time_frame_comparison(True, 1)
-        79.5±1ms       14.8±0.2ms     0.19  categoricals.Categoricals2.time_set_categories
-        3.45±0ms          439±3μs     0.13  timeseries.DatetimeIndex.time_timeseries_is_month_start
-           2.47s          231±2ms     0.09  sparse.sparse_frame_constructor.time_sparse_from_scipy
-     7.11±0.03μs          482±6ns     0.07  timestamp.TimestampProperties.time_weekday_name
-           2.46s          106±1ms     0.04  sparse.sparse_frame_constructor.time_sparse_from_dict
-        915±20μs       23.5±0.7μs     0.03  timeseries.DatetimeAccessor.time_dt_accessor
-       105±0.4ms      2.38±0.04ms     0.02  rolling.SeriesRolling.time_rolling_quantile_0
-         116±1ms      2.36±0.01ms     0.02  rolling.SeriesRolling.time_rolling_quantile_1
-       101±0.6ms      1.98±0.03ms     0.02  rolling.DataframeRolling.time_rolling_quantile_0
-      31.6±0.4μs          611±2ns     0.02  timestamp.TimestampOps.time_to_pydatetime_tz
-         123±2ms      1.99±0.03ms     0.02  rolling.DataframeRolling.time_rolling_quantile_1
-     10.1±0.09μs          147±1ns     0.01  timestamp.TimestampProperties.time_microsecond
-         197±1ms      2.55±0.03ms     0.01  rolling.SeriesRolling.time_rolling_quantile_0_l
-         201±1ms      2.13±0.04ms     0.01  rolling.DataframeRolling.time_rolling_quantile_0_l
-         260±1ms      2.49±0.04ms     0.01  rolling.SeriesRolling.time_rolling_quantile_1_l
-         263±2ms      2.17±0.02ms     0.01  rolling.DataframeRolling.time_rolling_quantile_1_l
-     3.51±0.02ms      4.59±0.04μs     0.00  hdfstore_bench.HDF5.time_store_repr
-     3.46±0.03ms      4.38±0.07μs     0.00  hdfstore_bench.HDF5.time_store_str
-      15.9±0.2ms      1.37±0.01μs     0.00  index_object.Range.time_min
-      16.1±0.3ms      1.35±0.01μs     0.00  index_object.Range.time_max
-      15.8±0.1ms      1.26±0.02μs     0.00  index_object.Range.time_max_trivial
-      16.0±0.1ms      1.23±0.02μs     0.00  index_object.Range.time_min_trivial

@jbrockmendel
Copy link
Member

-b timeseries.DatetimeIndex.time_infer_

These may be improved by #17830 and/or #17746.

@TomAugspurger
Copy link
Contributor Author

TomAugspurger commented Oct 25, 2017

For period.Algorithms.time_drop_duplicates_pseries, it seems like Period.freqstr is being called somewhere inside _ensure_data / ensure_object. Could that be avoided?

@jbrockmendel
Copy link
Member

Are you sure its freqstr in particular? It seems like drop_duplicates would make a bunch of calls to Period.__eq__, which then calls self.freq.__eq__(other.freq) which is very slow.

@TomAugspurger
Copy link
Contributor Author

I think it's in Period.__hash__, but confirming now.

@TomAugspurger
Copy link
Contributor Author

Hmm that may be it:

diff --git a/pandas/_libs/period.pyx b/pandas/_libs/period.pyx
index cf6ef91d3..f28ee2aac 100644
--- a/pandas/_libs/period.pyx
+++ b/pandas/_libs/period.pyx
@@ -718,7 +718,7 @@ cdef class _Period(object):
                             (type(self).__name__, type(other).__name__))

     def __hash__(self):
-        return hash((self.ordinal, self.freqstr))
+        return hash((self.ordinal, self.freq))

     def _add_delta(self, other):
         if isinstance(other, (timedelta, np.timedelta64, offsets.Tick)):
(

master:

In [1]: import pandas as pd

In [2]: p = pd.Period("2010", freq="M")

In [3]: %timeit hash(p)
807 ns ± 8.42 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

with that diff:


In [1]: import pandas as pd

In [2]: p = pd.Period("2010", freq="M")

In [3]: %timeit hash(p)
4.84 µs ± 42.1 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

Let's see if that breaks anything.

@jbrockmendel
Copy link
Member

Can you try that with a handful of different frequencies? I'd be shocked if hash(freq) is faster than hash(freq.freqstr)

@TomAugspurger
Copy link
Contributor Author

FWIW, it doesn't seem promising w.r.t. the benchmark (see the 2nd and 4th) lines. I rebuilt the c extensions between these two. My branch with the new hash is on top, master is on bottom.

 ◰³ pandas-dev  ~/E/p/l/p/s/pandas   period-freq-hash  asv_bench  asv dev -b 'period.Algorithms.time_[drop|value]'    4584ms  Wed Oct 25 14:12:40 2017
· Discovering benchmarks
· Running 4 total benchmarks (1 commits * 1 environments * 4 benchmarks)
[  0.00%] ·· Building for existing-py_Users_taugspurger_Envs_pandas-dev_bin_python3.6
[  0.00%] ·· Benchmarking existing-py_Users_taugspurger_Envs_pandas-dev_bin_python3.6
[ 25.00%] ··· Running period.Algorithms.time_drop_duplicates_pindex                                                                                   49.0μs
[ 50.00%] ··· Running period.Algorithms.time_drop_duplicates_pseries                                                                                  18.5ms
[ 75.00%] ··· Running period.Algorithms.time_value_counts_pindex                                                                                       402μs
[100.00%] ··· Running period.Algorithms.time_value_counts_pseries                                                                                     22.8ms
 ◰³ pandas-dev  ~/E/p/l/p/s/pandas   period-freq-hash  asv_bench  asv dev -b 'period.Algorithms.time_[drop|value]'        6s  Wed Oct 25 14:13:37 2017
· Discovering benchmarks
· Running 4 total benchmarks (1 commits * 1 environments * 4 benchmarks)
[  0.00%] ·· Building for existing-py_Users_taugspurger_Envs_pandas-dev_bin_python3.6
[  0.00%] ·· Benchmarking existing-py_Users_taugspurger_Envs_pandas-dev_bin_python3.6
[ 25.00%] ··· Running period.Algorithms.time_drop_duplicates_pindex                                                                                   48.0μs
[ 50.00%] ··· Running period.Algorithms.time_drop_duplicates_pseries                                                                                  3.14ms
[ 75.00%] ··· Running period.Algorithms.time_value_counts_pindex                                                                                       405μs
[100.00%] ··· Running period.Algorithms.time_value_counts_pseries                                                                                     3.43ms

@TomAugspurger
Copy link
Contributor Author

TomAugspurger commented Oct 25, 2017

@jreback if you have time to look at the indexing ones, I'd appreciate it: #17861 (comment) and #17861 (comment)

I'm not sure there's a whole lot to be done though. The first is because we have to check for missing values with list-like indexers now, to raise the warning.

@TomAugspurger
Copy link
Contributor Author

Oh, I'm dumb. Mixed up nanoseconds and microseconds in #17861 (comment)

@TomAugspurger
Copy link
Contributor Author

I think we decided in #17574 that the sparse changes were OK?

@jorisvandenbossche
Copy link
Member

@jreback if you have time to look at the indexing ones, I'd appreciate it: #17861 (comment) and #17861 (comment)

The series getitem ones (s[np.arange(10000)]) are due to changing reindex to loc, and apparently loc is slower.

@TomAugspurger
Copy link
Contributor Author

I think everything has been addressed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Performance Memory or execution speed performance
Projects
None yet
Development

No branches or pull requests

4 participants