Get users query makes the site loading time too big?

but this code makes the site loading time too big, and I don’t know
why!

I think that is just because you are getting quite a lot of stuff from the database with your code. Escpecially if your code runs on every single page load.

Here’s my suggestions,

Extra parameters to WP_Query to potentially make the query more efficient.

$args = array(
  'date_query' => array( array( 'after' => '1 week ago' ) ),
  'author' => $userss->ID,
  'post_type' => 'post',
  'numberposts' => -1,
  'cat' => '3',

  'no_found_rows' => true, // "useful when pagination is not needed", from https://10up.github.io/Engineering-Best-Practices/php/
  'fields' => 'ids', // no need for all post data if get_post_meta is only what the post data is used for
  'update_post_term_cache' => false, // not needed if you're not using terms in your loop 
);
$query = new WP_Query( $args );

As a personal experience, I’ve noticed that sometimes it makes sense to write your own sqlstatement and use it with $wpdb->prepare/get_results to get stuff out of the database faster.

Remove wp_reset_query(); from foreach loop

This probably just a minor tweak, but looking at the wp_reset_query Codex entry,

Calling wp_reset_query is not necessary after using WP_Query or
get_posts as these don’t modify the main query object. Instead use
wp_reset_postdata

And I don’t think you don’t need to use wp_reset_postdata() either as you’re not affecting the global $post variable.

Use transient cache

If new contributors and authors are not added very frequently, you could store $user_query->get_results(); into a transient, with sensible expiration time or refresh when new one is added, to skip doing WP_User_Query every single time.

If it fits your setup and situation, perhaps you could save $query = new WP_Query( $args ); for each user as a transient with expiration time of one day. Then update the transient with a cronjob, WP or a real one, daily.

If the view count doesn’t need to be exactly real-time, then perhaps you could consider saving the total result from $counter += $views; into a transient (maybe with a expiration time of one hour?) too.

So instead of querying every time, every post over the last week, for every user with correct role, you would be getting these with three get_transient calls.

Minor tweak to user sorting

I’m not sure, if this has any real effect on the performance, but I’m adding this at least as a curiosity.

// Instead of this
$topuser[] = array( 
  'id' => $userss->ID, 
  'viewz' => $counter
);

// You could do this
$topuser[$userss->ID] = $counter:

// So you can then use arsort() which
// sorts an associative array in descending order, according to the value:
arsort($topuser);

// Create also a helper array to go along with $topuser
$users_by_id[$userss->ID] = $userss;
// From which you can get user data with ID in your foreach ($output as $user) loop