@@ -2411,9 +2411,15 @@ static struct hist_field *parse_unary(struct hist_trigger_data *hist_data,
2411
2411
return ERR_PTR (ret );
2412
2412
}
2413
2413
2414
+ /*
2415
+ * If the operands are var refs, return pointers the
2416
+ * variable(s) referenced in var1 and var2, else NULL.
2417
+ */
2414
2418
static int check_expr_operands (struct trace_array * tr ,
2415
2419
struct hist_field * operand1 ,
2416
- struct hist_field * operand2 )
2420
+ struct hist_field * operand2 ,
2421
+ struct hist_field * * var1 ,
2422
+ struct hist_field * * var2 )
2417
2423
{
2418
2424
unsigned long operand1_flags = operand1 -> flags ;
2419
2425
unsigned long operand2_flags = operand2 -> flags ;
@@ -2426,6 +2432,7 @@ static int check_expr_operands(struct trace_array *tr,
2426
2432
if (!var )
2427
2433
return - EINVAL ;
2428
2434
operand1_flags = var -> flags ;
2435
+ * var1 = var ;
2429
2436
}
2430
2437
2431
2438
if ((operand2_flags & HIST_FIELD_FL_VAR_REF ) ||
@@ -2436,6 +2443,7 @@ static int check_expr_operands(struct trace_array *tr,
2436
2443
if (!var )
2437
2444
return - EINVAL ;
2438
2445
operand2_flags = var -> flags ;
2446
+ * var2 = var ;
2439
2447
}
2440
2448
2441
2449
if ((operand1_flags & HIST_FIELD_FL_TIMESTAMP_USECS ) !=
@@ -2453,9 +2461,12 @@ static struct hist_field *parse_expr(struct hist_trigger_data *hist_data,
2453
2461
char * var_name , unsigned int * n_subexprs )
2454
2462
{
2455
2463
struct hist_field * operand1 = NULL , * operand2 = NULL , * expr = NULL ;
2456
- unsigned long operand_flags ;
2464
+ struct hist_field * var1 = NULL , * var2 = NULL ;
2465
+ unsigned long operand_flags , operand2_flags ;
2457
2466
int field_op , ret = - EINVAL ;
2458
2467
char * sep , * operand1_str ;
2468
+ hist_field_fn_t op_fn ;
2469
+ bool combine_consts ;
2459
2470
2460
2471
if (* n_subexprs > 3 ) {
2461
2472
hist_err (file -> tr , HIST_ERR_TOO_MANY_SUBEXPR , errpos (str ));
@@ -2512,11 +2523,38 @@ static struct hist_field *parse_expr(struct hist_trigger_data *hist_data,
2512
2523
goto free ;
2513
2524
}
2514
2525
2515
- ret = check_expr_operands (file -> tr , operand1 , operand2 );
2526
+ switch (field_op ) {
2527
+ case FIELD_OP_MINUS :
2528
+ op_fn = hist_field_minus ;
2529
+ break ;
2530
+ case FIELD_OP_PLUS :
2531
+ op_fn = hist_field_plus ;
2532
+ break ;
2533
+ case FIELD_OP_DIV :
2534
+ op_fn = hist_field_div ;
2535
+ break ;
2536
+ case FIELD_OP_MULT :
2537
+ op_fn = hist_field_mult ;
2538
+ break ;
2539
+ default :
2540
+ ret = - EINVAL ;
2541
+ goto free ;
2542
+ }
2543
+
2544
+ ret = check_expr_operands (file -> tr , operand1 , operand2 , & var1 , & var2 );
2516
2545
if (ret )
2517
2546
goto free ;
2518
2547
2519
- flags |= HIST_FIELD_FL_EXPR ;
2548
+ operand_flags = var1 ? var1 -> flags : operand1 -> flags ;
2549
+ operand2_flags = var2 ? var2 -> flags : operand2 -> flags ;
2550
+
2551
+ /*
2552
+ * If both operands are constant, the expression can be
2553
+ * collapsed to a single constant.
2554
+ */
2555
+ combine_consts = operand_flags & operand2_flags & HIST_FIELD_FL_CONST ;
2556
+
2557
+ flags |= combine_consts ? HIST_FIELD_FL_CONST : HIST_FIELD_FL_EXPR ;
2520
2558
2521
2559
flags |= operand1 -> flags &
2522
2560
(HIST_FIELD_FL_TIMESTAMP | HIST_FIELD_FL_TIMESTAMP_USECS );
@@ -2533,37 +2571,43 @@ static struct hist_field *parse_expr(struct hist_trigger_data *hist_data,
2533
2571
expr -> operands [0 ] = operand1 ;
2534
2572
expr -> operands [1 ] = operand2 ;
2535
2573
2536
- /* The operand sizes should be the same, so just pick one */
2537
- expr -> size = operand1 -> size ;
2574
+ if (combine_consts ) {
2575
+ if (var1 )
2576
+ expr -> operands [0 ] = var1 ;
2577
+ if (var2 )
2578
+ expr -> operands [1 ] = var2 ;
2538
2579
2539
- expr -> operator = field_op ;
2540
- expr -> name = expr_str (expr , 0 );
2541
- expr -> type = kstrdup_const (operand1 -> type , GFP_KERNEL );
2542
- if (!expr -> type ) {
2543
- ret = - ENOMEM ;
2544
- goto free ;
2545
- }
2580
+ expr -> constant = op_fn (expr , NULL , NULL , NULL , NULL );
2546
2581
2547
- switch (field_op ) {
2548
- case FIELD_OP_MINUS :
2549
- expr -> fn = hist_field_minus ;
2550
- break ;
2551
- case FIELD_OP_PLUS :
2552
- expr -> fn = hist_field_plus ;
2553
- break ;
2554
- case FIELD_OP_DIV :
2555
- expr -> fn = hist_field_div ;
2556
- break ;
2557
- case FIELD_OP_MULT :
2558
- expr -> fn = hist_field_mult ;
2559
- break ;
2560
- default :
2561
- ret = - EINVAL ;
2562
- goto free ;
2582
+ expr -> operands [0 ] = NULL ;
2583
+ expr -> operands [1 ] = NULL ;
2584
+
2585
+ /*
2586
+ * var refs won't be destroyed immediately
2587
+ * See: destroy_hist_field()
2588
+ */
2589
+ destroy_hist_field (operand2 , 0 );
2590
+ destroy_hist_field (operand1 , 0 );
2591
+
2592
+ expr -> name = expr_str (expr , 0 );
2593
+ } else {
2594
+ expr -> fn = op_fn ;
2595
+
2596
+ /* The operand sizes should be the same, so just pick one */
2597
+ expr -> size = operand1 -> size ;
2598
+
2599
+ expr -> operator = field_op ;
2600
+ expr -> type = kstrdup_const (operand1 -> type , GFP_KERNEL );
2601
+ if (!expr -> type ) {
2602
+ ret = - ENOMEM ;
2603
+ goto free ;
2604
+ }
2605
+
2606
+ expr -> name = expr_str (expr , 0 );
2563
2607
}
2564
2608
2565
2609
return expr ;
2566
- free :
2610
+ free :
2567
2611
destroy_hist_field (operand1 , 0 );
2568
2612
destroy_hist_field (operand2 , 0 );
2569
2613
destroy_hist_field (expr , 0 );
0 commit comments