generate_queries( $query_count ); // Execute based on mode if ( $execution_mode === 'parallel' ) { error_log( 'MPSS: Executing in PARALLEL mode' ); $results = $this->run_parallel( $queries ); } else { error_log( 'MPSS: Executing in SERIAL mode' ); $results = $this->run_serial( $queries ); } $end_time = microtime( true ); $total_time = $end_time - $start_time; // Calculate statistics $times = array_column( $results, 'duration_ms' ); $avg_ms = array_sum( $times ) / count( $times ); $min_ms = min( $times ); $max_ms = max( $times ); return array( 'results' => $results, 'total_time' => round( $total_time, 2 ), 'total_queries' => count( $results ), 'avg_ms' => round( $avg_ms, 2 ), 'min_ms' => round( $min_ms, 2 ), 'max_ms' => round( $max_ms, 2 ), 'mode' => $execution_mode, ); } /** * Run queries in serial mode (one at a time). * * @param array $queries Array of search query strings. * @return array Results array. */ private function run_serial( $queries ) { $results = array(); foreach ( $queries as $query ) { $query_start = microtime( true ); // Make HTTP request to search URL to properly trigger MaplePress hooks $search_url = home_url( '/?s=' . urlencode( $query ) ); $response = wp_remote_get( $search_url, array( 'timeout' => 30, 'headers' => array( 'X-MaplePress-Test' => '1', ), ) ); $query_end = microtime( true ); $duration_ms = ( $query_end - $query_start ) * 1000; // Extract result count from response - try multiple patterns $result_count = 0; if ( ! is_wp_error( $response ) && wp_remote_retrieve_response_code( $response ) === 200 ) { $body = wp_remote_retrieve_body( $response ); // Try various patterns to find result count $patterns = array( '/(\d+)\s+results?/i', // "5 results" or "1 result" '/found\s+(\d+)/i', // "Found 5" '/showing\s+(\d+)/i', // "Showing 5" '/
]*class="[^"]*post[^"]*"/i', // Count post divs ); foreach ( $patterns as $pattern ) { if ( $pattern === '/
0 ) { $result_count = $count; break; } } else { // Extract number from text if ( preg_match( $pattern, $body, $matches ) ) { $result_count = intval( $matches[1] ); break; } } } } $results[] = array( 'query' => $query, 'duration_ms' => round( $duration_ms, 2 ), 'result_count' => $result_count, ); } return $results; } /** * Run queries in parallel mode (multiple concurrent requests). * * @param array $queries Array of search query strings. * @return array Results array. */ private function run_parallel( $queries ) { error_log( 'MPSS: run_parallel called with ' . count( $queries ) . ' queries' ); $results = array(); // Build search URLs $search_urls = array(); foreach ( $queries as $query ) { $search_urls[] = array( 'url' => home_url( '/?s=' . urlencode( $query ) ), 'query' => $query, ); } error_log( 'MPSS: Built ' . count( $search_urls ) . ' search URLs' ); // Initialize cURL multi handle $mh = curl_multi_init(); $curl_handles = array(); $request_info = array(); // Add all requests to multi handle foreach ( $search_urls as $index => $search_data ) { $ch = curl_init(); curl_setopt( $ch, CURLOPT_URL, $search_data['url'] ); curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true ); curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, true ); curl_setopt( $ch, CURLOPT_TIMEOUT, 30 ); curl_setopt( $ch, CURLOPT_HTTPHEADER, array( 'X-MaplePress-Test: 1', ) ); curl_multi_add_handle( $mh, $ch ); $ch_id = (int) $ch; $curl_handles[ $ch_id ] = $ch; $request_info[ $ch_id ] = array( 'query' => $search_data['query'], 'index' => $index, 'start_time' => null, 'end_time' => null, ); } error_log( 'MPSS: Added ' . count( $curl_handles ) . ' handles, request_info has ' . count( $request_info ) . ' entries' ); // Execute all queries simultaneously and track start/end times $running = null; // Record start time for ALL requests (they all start together) $batch_start = microtime( true ); foreach ( $request_info as $ch_id => $info ) { $request_info[ $ch_id ]['start_time'] = $batch_start; } // Start executing - all requests run concurrently do { curl_multi_exec( $mh, $running ); // Check for completed requests and record their end time while ( $done = curl_multi_info_read( $mh ) ) { if ( $done['msg'] == CURLMSG_DONE ) { $ch_id = (int) $done['handle']; // Record when THIS specific request finished if ( ! isset( $request_info[ $ch_id ]['end_time'] ) ) { $request_info[ $ch_id ]['end_time'] = microtime( true ); } } } if ( $running > 0 ) { curl_multi_select( $mh ); } } while ( $running > 0 ); $batch_end = microtime( true ); $batch_duration_ms = ( $batch_end - $batch_start ) * 1000; error_log( 'MPSS: Batch completed in ' . round( $batch_duration_ms, 2 ) . 'ms, processing ' . count( $request_info ) . ' results' ); // Collect results - calculate duration from start/end times foreach ( $request_info as $ch_id => $info ) { $ch = $curl_handles[ $ch_id ]; // Calculate duration from start to end time if ( isset( $info['start_time'] ) && isset( $info['end_time'] ) ) { $duration_seconds = $info['end_time'] - $info['start_time']; $duration_ms = $duration_seconds * 1000; // Debug: log a few samples static $debug_count = 0; if ( $debug_count < 3 ) { error_log( sprintf( 'MPSS: Sample #%d - start=%.6f, end=%.6f, duration_sec=%.6f, duration_ms=%.2f', $debug_count, $info['start_time'], $info['end_time'], $duration_seconds, $duration_ms ) ); $debug_count++; } } else { // Fallback - shouldn't happen $duration_ms = 0; } $curl_info = curl_getinfo( $ch ); $response = curl_multi_getcontent( $ch ); $http_code = $curl_info['http_code']; // Extract result count using multiple patterns $result_count = 0; if ( $http_code === 200 && ! empty( $response ) ) { $patterns = array( '/(\d+)\s+results?/i', '/found\s+(\d+)/i', '/showing\s+(\d+)/i', '/
]*class="[^"]*post[^"]*"/i', ); foreach ( $patterns as $pattern ) { if ( $pattern === '/
0 ) { $result_count = $count; break; } } else { if ( preg_match( $pattern, $response, $matches ) ) { $result_count = intval( $matches[1] ); break; } } } } $results[ $info['index'] ] = array( 'query' => $info['query'], 'duration_ms' => round( $duration_ms, 2 ), 'result_count' => $result_count, ); curl_multi_remove_handle( $mh, $ch ); curl_close( $ch ); } curl_multi_close( $mh ); // Sort results by original index to maintain query order ksort( $results ); return array_values( $results ); } /** * Generate random search queries from existing content. * * @param int $count Number of queries to generate. * @return array Array of search query strings. */ private function generate_queries( $count ) { error_log( 'MPSS: generate_queries called with count=' . $count ); $posts = get_posts( array( 'post_type' => array( 'post', 'page' ), 'post_status' => 'publish', 'posts_per_page' => $count * 3, 'orderby' => 'rand', ) ); error_log( 'MPSS: get_posts returned ' . count( $posts ) . ' posts' ); $queries = array(); foreach ( $posts as $post ) { if ( count( $queries ) >= $count ) { break; } // Get words from title $words = array_filter( explode( ' ', $post->post_title ) ); if ( empty( $words ) ) { continue; } // 50% single word, 50% two words if ( mt_rand( 1, 2 ) === 1 || count( $words ) === 1 ) { $queries[] = $words[ array_rand( $words ) ]; } else { $start = mt_rand( 0, count( $words ) - 2 ); $queries[] = $words[ $start ] . ' ' . $words[ $start + 1 ]; } } // If we don't have enough, pad with generic searches while ( count( $queries ) < $count ) { $queries[] = 'test'; } $final_queries = array_slice( $queries, 0, $count ); error_log( 'MPSS: generate_queries returning ' . count( $final_queries ) . ' queries' ); return $final_queries; } }